<commit_before>//----------------------------  trilinos_vector_reinit.cc  ---------------------------
//    $Id: trilinos_vector_reinit.cc 23710 2011-05-17 04:50:10Z bangerth $
//    Version: $Name$
//
//    Copyright (C) 2011 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.
//
//----------------------------  trilinos_vector_reinit.cc  ---------------------------

// document a bug in Trilinos regarding compress()

#include "../tests.h"
#include <deal.II/base/utilities.h>
#include <deal.II/base/index_set.h>
#include <deal.II/lac/trilinos_vector.h>
#include <deal.II/lac/constraint_matrix.h>
#include <fstream>
#include <iostream>
#include <vector>
#include "../../deal.II/include/deal.II/base/index_set.h"
#include "../../deal.II/include/deal.II/lac/trilinos_vector.h"

void test ()
{
  unsigned int myid = Utilities::System::get_this_mpi_process (MPI_COMM_WORLD);
  unsigned int numproc = Utilities::System::get_n_mpi_processes (MPI_COMM_WORLD);

  if (myid==0) deallog << "numproc=" << numproc << std::endl;

  IndexSet locally_owned(21);
  if (myid==0)
    locally_owned.add_range(0,9);
  else
    locally_owned.add_range(9,21);

  TrilinosWrappers::MPI::Vector test1(locally_owned);
  if (myid==0)
  {
    unsigned int idx[]={0,1,2,3,4,5,6,7,8};
    double val[]={0,1,2,3,4,5,6,7,8};
    test1.add(9,idx,val);
  }
  else
  {
   {
      unsigned int idx[]={1,9,3,10,5,11,12,13,14};
    double val[]={1,9,3,10,5,11,12,13,14};
    test1.add(9,idx,val);
    }
  }

  test1.compress(Add);
  TrilinosWrappers::MPI::Vector test(locally_owned);
  //  TrilinosWrappers::MPI::Vector test(test1);

  test = 0;

  if (myid==0)
    test(locally_owned.nth_index_in_set(5))=7;

  if (myid==0)
    deallog << "before compress: " << test(locally_owned.nth_index_in_set(5)) << endl;

   test.compress(Insert);
  if (myid==0)
    deallog << "after compress: " << test(locally_owned.nth_index_in_set(5)) << endl;

  // Trilinos produces a 0 instead of a 7 here. Why?
  Assert(test(locally_owned.nth_index_in_set(5)) == 7, ExcInternalError());

  if (Utilities::System::get_this_mpi_process (MPI_COMM_WORLD) == 0)
    deallog << "OK" << std::endl;
}

int main (int argc, char **argv)
{
  Utilities::System::MPI_InitFinalize mpi_initialization(argc, argv);

  unsigned int myid = Utilities::System::get_this_mpi_process (MPI_COMM_WORLD);
  deallog.push(Utilities::int_to_string(myid));

  if (myid == 0)
    {
      std::ofstream logfile(output_file_for_mpi("trilinos_compress_bug").c_str());
      deallog.attach(logfile);
      deallog << std::setprecision(4);
      deallog.depth_console(0);
      deallog.threshold_double(1.e-10);

      test();
    }
  else
    test();

}
<commit_msg>fix test for bug in trilinos compress()<commit_after>//----------------------------  trilinos_vector_reinit.cc  ---------------------------
//    $Id: trilinos_vector_reinit.cc 23710 2011-05-17 04:50:10Z bangerth $
//    Version: $Name$
//
//    Copyright (C) 2011 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.
//
//----------------------------  trilinos_vector_reinit.cc  ---------------------------

// document a bug in Trilinos regarding compress()

#include "../tests.h"
#include <deal.II/base/utilities.h>
#include <deal.II/base/index_set.h>
#include <deal.II/lac/trilinos_vector.h>
#include <deal.II/lac/constraint_matrix.h>
#include <fstream>
#include <iostream>
#include <vector>
#include "../../deal.II/include/deal.II/base/index_set.h"
#include "../../deal.II/include/deal.II/lac/trilinos_vector.h"

void test ()
{
  unsigned int myid = Utilities::System::get_this_mpi_process (MPI_COMM_WORLD);
  unsigned int numproc = Utilities::System::get_n_mpi_processes (MPI_COMM_WORLD);

  if (myid==0) deallog << "numproc=" << numproc << std::endl;

  IndexSet locally_owned(21);
  if (myid==0)
    locally_owned.add_range(0,9);
  else
    locally_owned.add_range(9,21);
//
  TrilinosWrappers::MPI::Vector test1(locally_owned);
  if (myid==0)
  {
    unsigned int idx[]={0,1,2,3,4,5,6,7,8};
    double val[]={0,1,2,3,4,5,6,7,8};
    test1.add(9,idx,val);
  }
  else
  {
   {
      unsigned int idx[]={1,9,3,10,5,11,12,13,14};
    double val[]={1,9,3,10,5,11,12,13,14};
    test1.add(9,idx,val);
    }
  }

  test1.compress(Add);

  //TrilinosWrappers::MPI::Vector test(test1.vector_partitioner()); // works
  //TrilinosWrappers::MPI::Vector test(locally_owned); // works
  TrilinosWrappers::MPI::Vector test(test1); // fails

  test = 0;

  if (myid==0)
    test(locally_owned.nth_index_in_set(5))=7;

  if (myid==0)
    deallog << "before compress: " << test(locally_owned.nth_index_in_set(5)) << endl;

   test.compress(Insert);

  if (myid==0)
    deallog << "after compress: " << test(locally_owned.nth_index_in_set(5)) << endl;

  // Trilinos produces a 0 instead of a 7 here. Why?
  if (myid==0)
  {
    Assert(test(locally_owned.nth_index_in_set(5)) == 7, ExcInternalError());
  }

  if (Utilities::System::get_this_mpi_process (MPI_COMM_WORLD) == 0)
    deallog << "OK" << std::endl;
}

int main (int argc, char **argv)
{
  Utilities::System::MPI_InitFinalize mpi_initialization(argc, argv);

  unsigned int myid = Utilities::System::get_this_mpi_process (MPI_COMM_WORLD);
  deallog.push(Utilities::int_to_string(myid));

  if (myid == 0)
    {
      std::ofstream logfile(output_file_for_mpi("trilinos_compress_bug").c_str());
      deallog.attach(logfile);
      deallog << std::setprecision(4);
      deallog.depth_console(0);
      deallog.threshold_double(1.e-10);

      test();
    }
  else
    test();

}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "list.h"

#include <QtCore/QDebug>

#include "storage/datastore.h"
#include "storage/entity.h"
#include "storage/selectquerybuilder.h"

#include "akonadiconnection.h"
#include "response.h"
#include "handlerhelper.h"
#include "imapstreamparser.h"

#include <libs/protocol_p.h>
#include <storage/collectionqueryhelper.h>

using namespace Akonadi;

template <typename T>
static bool intersect( const QVector<typename T::Id> &l1, const QVector<T> &l2 )
{
  foreach ( const T& e2, l2 ) {
    if ( l1.contains( e2.id() ) )
      return true;
  }
  return false;
}

List::List( Scope::SelectionScope scope, bool onlySubscribed ):
    Handler(),
    mScope( scope ),
    mAncestorDepth( 0 ),
    mOnlySubscribed( onlySubscribed ),
    mIncludeStatistics( false )
{}

QStack<Collection> List::ancestorsForCollection( const Collection &col )
{
  if ( mAncestorDepth <= 0 )
    return QStack<Collection>();
  QStack<Collection> ancestors;
  Collection parent = col.parent();
  for ( int i = 0; i < mAncestorDepth; ++i ) {
    if ( !parent.isValid() )
      break;
    ancestors.prepend( parent );
    parent = parent.parent();
  }
  return ancestors;
}

bool List::listCollection(const Collection & root, int depth, const QStack<Collection> &ancestors )
{
  // recursive listing of child collections
  bool childrenFound = false;
  if ( depth > 0 ) {
    Collection::List children = root.children();
    QStack<Collection> ancestorsAndMe( ancestors );
    ancestorsAndMe.push( root );
    foreach ( const Collection &col, children ) {
      if ( listCollection( col, depth - 1, ancestorsAndMe ) )
        childrenFound = true;
    }
  }

  // filter if this node isn't needed by it's children
  bool hidden = (mResource.isValid() && root.resourceId() != mResource.id())
      || (mOnlySubscribed && !root.subscribed())
      || (!mMimeTypes.isEmpty() && !intersect( mMimeTypes, root.mimeTypes()) );

  if ( !childrenFound && hidden )
    return false;

  // write out collection details
  Collection dummy = root;
  DataStore *db = connection()->storageBackend();
  db->activeCachePolicy( dummy );
  const QByteArray b = HandlerHelper::collectionToByteArray( dummy, hidden, mIncludeStatistics, mAncestorDepth, ancestors );

  Response response;
  response.setUntagged();
  response.setString( b );
  emit responseAvailable( response );

  return true;
}

bool List::parseStream()
{
  qint64 baseCollection = -1;
  QString rid;
  if ( mScope.scope() == Scope::None || mScope.scope() == Scope::Uid ) {
    bool ok = false;
    baseCollection = m_streamParser->readNumber( &ok );
    if ( !ok )
      return failureResponse( "Invalid base collection" );
  } else if ( mScope.scope() == Scope::Rid ) {
    rid = m_streamParser->readUtf8String();
    if ( rid.isEmpty() )
      throw HandlerException( "No remote identifier specified" );
  } else if ( mScope.scope() == Scope::HierarchicalRid ) {
    mScope.parseScope( m_streamParser );
  } else
    throw HandlerException( "WTF" );

  int depth = HandlerHelper::parseDepth( m_streamParser->readString() );

  m_streamParser->beginList();
  while ( !m_streamParser->atListEnd() ) {
    const QByteArray filter = m_streamParser->readString();
    if ( filter == AKONADI_PARAM_RESOURCE ) {
      mResource = Resource::retrieveByName( m_streamParser->readUtf8String() );
      if ( !mResource.isValid() )
        return failureResponse( "Unknown resource" );
    } else if ( filter == AKONADI_PARAM_MIMETYPE ) {
      m_streamParser->beginList();
      while ( !m_streamParser->atListEnd() ) {
        const QString mtName = m_streamParser->readUtf8String();
        const MimeType mt = MimeType::retrieveByName( mtName );
        if ( mt.isValid() ) {
          mMimeTypes.append( mt.id() );
        } else {
          MimeType mt ( mtName );
          if ( !mt.insert() )
            throw HandlerException( "Failed to create mimetype record" );
          mMimeTypes.append( mt.id() );
        }
      }
    }
  }

  if ( m_streamParser->hasList() ) { // We got extra options
    m_streamParser->beginList();
    while ( !m_streamParser->atListEnd() ) {
      const QByteArray option = m_streamParser->readString();
      if ( option == "STATISTICS" ) {
        if ( m_streamParser->readString() == "true" )
          mIncludeStatistics = true;
      }
      if ( option == AKONADI_PARAM_ANCESTORS ) {
        const QByteArray argument = m_streamParser->readString();
        mAncestorDepth = HandlerHelper::parseDepth( argument );
      }
    }
  }

  Collection::List collections;
  QStack<Collection> ancestors;

  if ( baseCollection != 0 ) { // not root
    Collection col;
    if ( mScope.scope() == Scope::None || mScope.scope() == Scope::Uid ) {
       col = Collection::retrieveById( baseCollection );
    } else if ( mScope.scope() == Scope::Rid ) {
      SelectQueryBuilder<Collection> qb;
      qb.addValueCondition( Collection::remoteIdFullColumnName(), Query::Equals, rid );
      qb.addJoin( QueryBuilder::InnerJoin, Resource::tableName(),
                  Collection::resourceIdFullColumnName(), Resource::idFullColumnName() );
      if ( mResource.isValid() )
        qb.addValueCondition( Resource::idFullColumnName(), Query::Equals, mResource.id() );
      else if ( connection()->resourceContext().isValid() )
        qb.addValueCondition( Resource::idFullColumnName(), Query::Equals, connection()->resourceContext().id() );
      else
        throw HandlerException( "Cannot retrieve collection based on remote identifier without a resource context" );
      if ( !qb.exec() )
        throw HandlerException( "Unable to retrieve collection for listing" );
      Collection::List results = qb.result();
      if ( results.count() != 1 )
        throw HandlerException( QByteArray::number( results.count() ) + " collections found" );
      col = results.first();
    } else if ( mScope.scope() == Scope::HierarchicalRid ) {
      if ( !connection()->resourceContext().isValid() )
        throw HandlerException( "Cannot retrieve collection based on hierarchical remote identifier without a resource context" );
      col = CollectionQueryHelper::resolveHierarchicalRID( mScope.ridChain(), connection()->resourceContext().id() );
    } else {
      throw HandlerException( "WTF" );
    }

    if ( !col.isValid() )
      return failureResponse( "Collection " + QByteArray::number( baseCollection ) + " does not exist" );

    if ( depth == 0 ) {
      collections << col;
      ancestors = ancestorsForCollection( col );
    } else {
      collections << col.children();
      --depth;
      if ( !collections.isEmpty() )
        ancestors = ancestorsForCollection( collections.first() );
    }
  } else {
    if ( depth != 0 ) {
      Collection::List list = Collection::retrieveFiltered( Collection::parentIdColumn(), QVariant() );
      collections << list;
    }
    --depth;
  }

  foreach ( const Collection &col, collections )
    listCollection( col, depth, ancestors );

  Response response;
  response.setSuccess();
  response.setTag( tag() );
  response.setString( "List completed" );
  emit responseAvailable( response );
  return true;
}

#include "list.moc"
<commit_msg>Stop iterating here one round earlier.<commit_after>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "list.h"

#include <QtCore/QDebug>

#include "storage/datastore.h"
#include "storage/entity.h"
#include "storage/selectquerybuilder.h"

#include "akonadiconnection.h"
#include "response.h"
#include "handlerhelper.h"
#include "imapstreamparser.h"

#include <libs/protocol_p.h>
#include <storage/collectionqueryhelper.h>

using namespace Akonadi;

template <typename T>
static bool intersect( const QVector<typename T::Id> &l1, const QVector<T> &l2 )
{
  foreach ( const T& e2, l2 ) {
    if ( l1.contains( e2.id() ) )
      return true;
  }
  return false;
}

List::List( Scope::SelectionScope scope, bool onlySubscribed ):
    Handler(),
    mScope( scope ),
    mAncestorDepth( 0 ),
    mOnlySubscribed( onlySubscribed ),
    mIncludeStatistics( false )
{}

QStack<Collection> List::ancestorsForCollection( const Collection &col )
{
  if ( mAncestorDepth <= 0 )
    return QStack<Collection>();
  QStack<Collection> ancestors;
  Collection parent = col;
  for ( int i = 0; i < mAncestorDepth; ++i ) {
    if ( parent.parentId() == 0 )
      break;
    parent = parent.parent();
    ancestors.prepend( parent );
  }
  return ancestors;
}

bool List::listCollection(const Collection & root, int depth, const QStack<Collection> &ancestors )
{
  // recursive listing of child collections
  bool childrenFound = false;
  if ( depth > 0 ) {
    Collection::List children = root.children();
    QStack<Collection> ancestorsAndMe( ancestors );
    ancestorsAndMe.push( root );
    foreach ( const Collection &col, children ) {
      if ( listCollection( col, depth - 1, ancestorsAndMe ) )
        childrenFound = true;
    }
  }

  // filter if this node isn't needed by it's children
  bool hidden = (mResource.isValid() && root.resourceId() != mResource.id())
      || (mOnlySubscribed && !root.subscribed())
      || (!mMimeTypes.isEmpty() && !intersect( mMimeTypes, root.mimeTypes()) );

  if ( !childrenFound && hidden )
    return false;

  // write out collection details
  Collection dummy = root;
  DataStore *db = connection()->storageBackend();
  db->activeCachePolicy( dummy );
  const QByteArray b = HandlerHelper::collectionToByteArray( dummy, hidden, mIncludeStatistics, mAncestorDepth, ancestors );

  Response response;
  response.setUntagged();
  response.setString( b );
  emit responseAvailable( response );

  return true;
}

bool List::parseStream()
{
  qint64 baseCollection = -1;
  QString rid;
  if ( mScope.scope() == Scope::None || mScope.scope() == Scope::Uid ) {
    bool ok = false;
    baseCollection = m_streamParser->readNumber( &ok );
    if ( !ok )
      return failureResponse( "Invalid base collection" );
  } else if ( mScope.scope() == Scope::Rid ) {
    rid = m_streamParser->readUtf8String();
    if ( rid.isEmpty() )
      throw HandlerException( "No remote identifier specified" );
  } else if ( mScope.scope() == Scope::HierarchicalRid ) {
    mScope.parseScope( m_streamParser );
  } else
    throw HandlerException( "WTF" );

  int depth = HandlerHelper::parseDepth( m_streamParser->readString() );

  m_streamParser->beginList();
  while ( !m_streamParser->atListEnd() ) {
    const QByteArray filter = m_streamParser->readString();
    if ( filter == AKONADI_PARAM_RESOURCE ) {
      mResource = Resource::retrieveByName( m_streamParser->readUtf8String() );
      if ( !mResource.isValid() )
        return failureResponse( "Unknown resource" );
    } else if ( filter == AKONADI_PARAM_MIMETYPE ) {
      m_streamParser->beginList();
      while ( !m_streamParser->atListEnd() ) {
        const QString mtName = m_streamParser->readUtf8String();
        const MimeType mt = MimeType::retrieveByName( mtName );
        if ( mt.isValid() ) {
          mMimeTypes.append( mt.id() );
        } else {
          MimeType mt ( mtName );
          if ( !mt.insert() )
            throw HandlerException( "Failed to create mimetype record" );
          mMimeTypes.append( mt.id() );
        }
      }
    }
  }

  if ( m_streamParser->hasList() ) { // We got extra options
    m_streamParser->beginList();
    while ( !m_streamParser->atListEnd() ) {
      const QByteArray option = m_streamParser->readString();
      if ( option == "STATISTICS" ) {
        if ( m_streamParser->readString() == "true" )
          mIncludeStatistics = true;
      }
      if ( option == AKONADI_PARAM_ANCESTORS ) {
        const QByteArray argument = m_streamParser->readString();
        mAncestorDepth = HandlerHelper::parseDepth( argument );
      }
    }
  }

  Collection::List collections;
  QStack<Collection> ancestors;

  if ( baseCollection != 0 ) { // not root
    Collection col;
    if ( mScope.scope() == Scope::None || mScope.scope() == Scope::Uid ) {
       col = Collection::retrieveById( baseCollection );
    } else if ( mScope.scope() == Scope::Rid ) {
      SelectQueryBuilder<Collection> qb;
      qb.addValueCondition( Collection::remoteIdFullColumnName(), Query::Equals, rid );
      qb.addJoin( QueryBuilder::InnerJoin, Resource::tableName(),
                  Collection::resourceIdFullColumnName(), Resource::idFullColumnName() );
      if ( mResource.isValid() )
        qb.addValueCondition( Resource::idFullColumnName(), Query::Equals, mResource.id() );
      else if ( connection()->resourceContext().isValid() )
        qb.addValueCondition( Resource::idFullColumnName(), Query::Equals, connection()->resourceContext().id() );
      else
        throw HandlerException( "Cannot retrieve collection based on remote identifier without a resource context" );
      if ( !qb.exec() )
        throw HandlerException( "Unable to retrieve collection for listing" );
      Collection::List results = qb.result();
      if ( results.count() != 1 )
        throw HandlerException( QByteArray::number( results.count() ) + " collections found" );
      col = results.first();
    } else if ( mScope.scope() == Scope::HierarchicalRid ) {
      if ( !connection()->resourceContext().isValid() )
        throw HandlerException( "Cannot retrieve collection based on hierarchical remote identifier without a resource context" );
      col = CollectionQueryHelper::resolveHierarchicalRID( mScope.ridChain(), connection()->resourceContext().id() );
    } else {
      throw HandlerException( "WTF" );
    }

    if ( !col.isValid() )
      return failureResponse( "Collection " + QByteArray::number( baseCollection ) + " does not exist" );

    if ( depth == 0 ) {
      collections << col;
      ancestors = ancestorsForCollection( col );
    } else {
      collections << col.children();
      --depth;
      if ( !collections.isEmpty() )
        ancestors = ancestorsForCollection( collections.first() );
    }
  } else {
    if ( depth != 0 ) {
      Collection::List list = Collection::retrieveFiltered( Collection::parentIdColumn(), QVariant() );
      collections << list;
    }
    --depth;
  }

  foreach ( const Collection &col, collections )
    listCollection( col, depth, ancestors );

  Response response;
  response.setSuccess();
  response.setTag( tag() );
  response.setString( "List completed" );
  emit responseAvailable( response );
  return true;
}

#include "list.moc"
<|endoftext|>


<commit_before>/**
 * get_localdate.cpp
 *
 * Copyright 2010 Florian Weber <florian.weber@sfz-bw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
**/

#include "date.hpp"

#include <cstdio>
#include <ctime>
#include <clocale>
#include <cstring>

using namespace std;

string get_localdate(){
	time_t TIME;
	char timestring[51];
	struct tm *timeinfo;
	std::string returnstring;
	setlocale(LC_ALL, "");
	time(&TIME);
	timeinfo=localtime(&TIME);
	strftime(timestring_1,50,"%A,%e. %B %Y",timeinfo);

	timestring[50]=0;

	return string(timestring);
}
<commit_msg> small fix<commit_after>/**
 * get_localdate.cpp
 *
 * Copyright 2010 Florian Weber <florian.weber@sfz-bw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
**/

#include "date.hpp"

#include <cstdio>
#include <ctime>
#include <clocale>
#include <cstring>

using namespace std;

string get_localdate(){
	time_t TIME;
	char timestring[51];
	struct tm *timeinfo;
	setlocale(LC_ALL, "");
	time(&TIME);
	timeinfo=localtime(&TIME);
	strftime(timestring,50,"%A,%e. %B %Y",timeinfo);

	timestring[50]=0;

	return string(timestring);
}
<|endoftext|>


<commit_before>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdexcept>
#include <cstring>
#include <cassert>
#include "utils.h"
#include "dhcp.h"

const uint32_t Tins::DHCP::MAX_DHCP_SIZE = 312;

using namespace std;

/* Magic cookie: uint32_t.
 * end of options: 1 byte. */
Tins::DHCP::DHCP() : _size(sizeof(uint32_t) + 1) {
    opcode(BOOTREQUEST);
    htype(1); //ethernet
    hlen(6);
}

Tins::DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) : BootP(buffer, total_sz, 0) {
    buffer += BootP::header_size();
    total_sz -= BootP::header_size();
    uint8_t args[2] = {0};
    while(total_sz) {
        for(unsigned i(0); i < 2 && args[0] != END; ++i) {
            args[i] = *(buffer++);
            total_sz--;
            if(!total_sz)
                throw std::runtime_error("Not enought size for a DHCP header in the buffer.");
        }
        // If the END-OF-OPTIONS was not found...
        if(args[0] != END) {
            // Not enough size for this option
            if(total_sz < args[1])
                throw std::runtime_error("Not enought size for a DHCP header in the buffer.");
            add_option((Options)args[0], args[1], buffer);
            buffer += args[1];
            total_sz -= args[1];
        }
        // Otherwise, break the loop.
        else
            total_sz = 0;
    }
}

Tins::DHCP::~DHCP() {
    while(_options.size()) {
        delete[] _options.front().value;
        _options.pop_front();
    }
}

Tins::DHCP::DHCPOption::DHCPOption(uint8_t opt, uint8_t len, const uint8_t *val) : option(opt), length(len) {
    value = new uint8_t[len];
    std::memcpy(value, val, len);
}

bool Tins::DHCP::add_option(Options opt, uint8_t len, const uint8_t *val) {
    uint32_t opt_size = len + (sizeof(uint8_t) << 1);
    if(_size + opt_size > MAX_DHCP_SIZE)
        return false;
    _options.push_back(DHCPOption((uint8_t)opt, len, val));
    _size += opt_size;
    return true;
}

bool Tins::DHCP::add_type_option(Flags type) {
    return add_option(DHCP_MESSAGE_TYPE, 1, (const uint8_t*)&type);
}

bool Tins::DHCP::add_server_identifier(uint32_t ip) {
    return add_option(DHCP_SERVER_IDENTIFIER, 4, (const uint8_t*)&ip);
}

bool Tins::DHCP::add_lease_time(uint32_t time) {
    time = Utils::net_to_host_l(time);
    return add_option(DHCP_LEASE_TIME, 4, (const uint8_t*)&time);
}

bool Tins::DHCP::add_subnet_mask(uint32_t mask) {
    return add_option(SUBNET_MASK, 4, (const uint8_t*)&mask);
}

bool Tins::DHCP::add_routers_option(const list<uint32_t> &routers) {
    uint32_t size;
    uint8_t *buffer = serialize_list(routers, size);
    bool ret = add_option(ROUTERS, size, buffer);
    delete[] buffer;
    return ret;
}

bool Tins::DHCP::add_dns_options(const list<uint32_t> &dns) {
    uint32_t size;
    uint8_t *buffer = serialize_list(dns, size);
    bool ret = add_option(DOMAIN_NAME_SERVERS, size, buffer);
    delete[] buffer;
    return ret;
}

bool Tins::DHCP::add_broadcast_option(uint32_t addr) {
    return add_option(BROADCAST_ADDRESS, 4, (uint8_t*)&addr);
}

bool Tins::DHCP::add_domain_name(const string &name) {
    return add_option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str());
}

uint8_t *Tins::DHCP::serialize_list(const list<uint32_t> &int_list, uint32_t &sz) {
    uint8_t *buffer = new uint8_t[int_list.size() * sizeof(uint32_t)];
    uint32_t *ptr = (uint32_t*)buffer;
    for(list<uint32_t>::const_iterator it = int_list.begin(); it != int_list.end(); ++it)
        *(ptr++) = *it;
    sz = sizeof(uint32_t) * int_list.size();
    return buffer;
}

uint32_t Tins::DHCP::header_size() const {
    return BootP::header_size() - vend_size() + _size;
}

void Tins::DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
    assert(total_sz >= header_size());
    uint8_t *result = new uint8_t[_size], *ptr = result + sizeof(uint32_t);
    // Magic cookie
    *((uint32_t*)result) = Utils::net_to_host_l(0x63825363);
    for(std::list<DHCPOption>::const_iterator it = _options.begin(); it != _options.end(); ++it) {
        *(ptr++) = it->option;
        *(ptr++) = it->length;
        std::memcpy(ptr, it->value, it->length);
        ptr += it->length;
    }
    // End of options
    result[_size-1] = END;
    vend(result, _size);
    BootP::write_serialization(buffer, total_sz, parent);
    delete[] result;
}

<commit_msg>Fixed bug triggered by sending DHCP with no options.<commit_after>/*
 * libtins is a net packet wrapper library for crafting and
 * interpreting sniffed packets.
 *
 * Copyright (C) 2011 Nasel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdexcept>
#include <cstring>
#include <cassert>
#include "utils.h"
#include "dhcp.h"

const uint32_t Tins::DHCP::MAX_DHCP_SIZE = 312;

using namespace std;

/* Magic cookie: uint32_t.
 * end of options: 1 byte. */
Tins::DHCP::DHCP() : _size(sizeof(uint32_t) + 1) {
    opcode(BOOTREQUEST);
    htype(1); //ethernet
    hlen(6);
}

Tins::DHCP::DHCP(const uint8_t *buffer, uint32_t total_sz) : BootP(buffer, total_sz, 0) {
    buffer += BootP::header_size();
    total_sz -= BootP::header_size();
    uint8_t args[2] = {0};
    while(total_sz) {
        for(unsigned i(0); i < 2 && args[0] != END; ++i) {
            args[i] = *(buffer++);
            total_sz--;
            if(!total_sz)
                throw std::runtime_error("Not enought size for a DHCP header in the buffer.");
        }
        // If the END-OF-OPTIONS was not found...
        if(args[0] != END) {
            // Not enough size for this option
            if(total_sz < args[1])
                throw std::runtime_error("Not enought size for a DHCP header in the buffer.");
            add_option((Options)args[0], args[1], buffer);
            buffer += args[1];
            total_sz -= args[1];
        }
        // Otherwise, break the loop.
        else
            total_sz = 0;
    }
}

Tins::DHCP::~DHCP() {
    while(_options.size()) {
        delete[] _options.front().value;
        _options.pop_front();
    }
}

Tins::DHCP::DHCPOption::DHCPOption(uint8_t opt, uint8_t len, const uint8_t *val) : option(opt), length(len) {
    value = new uint8_t[len];
    std::memcpy(value, val, len);
}

bool Tins::DHCP::add_option(Options opt, uint8_t len, const uint8_t *val) {
    uint32_t opt_size = len + (sizeof(uint8_t) << 1);
    if(_size + opt_size > MAX_DHCP_SIZE)
        return false;
    _options.push_back(DHCPOption((uint8_t)opt, len, val));
    _size += opt_size;
    return true;
}

bool Tins::DHCP::add_type_option(Flags type) {
    return add_option(DHCP_MESSAGE_TYPE, 1, (const uint8_t*)&type);
}

bool Tins::DHCP::add_server_identifier(uint32_t ip) {
    return add_option(DHCP_SERVER_IDENTIFIER, 4, (const uint8_t*)&ip);
}

bool Tins::DHCP::add_lease_time(uint32_t time) {
    time = Utils::net_to_host_l(time);
    return add_option(DHCP_LEASE_TIME, 4, (const uint8_t*)&time);
}

bool Tins::DHCP::add_subnet_mask(uint32_t mask) {
    return add_option(SUBNET_MASK, 4, (const uint8_t*)&mask);
}

bool Tins::DHCP::add_routers_option(const list<uint32_t> &routers) {
    uint32_t size;
    uint8_t *buffer = serialize_list(routers, size);
    bool ret = add_option(ROUTERS, size, buffer);
    delete[] buffer;
    return ret;
}

bool Tins::DHCP::add_dns_options(const list<uint32_t> &dns) {
    uint32_t size;
    uint8_t *buffer = serialize_list(dns, size);
    bool ret = add_option(DOMAIN_NAME_SERVERS, size, buffer);
    delete[] buffer;
    return ret;
}

bool Tins::DHCP::add_broadcast_option(uint32_t addr) {
    return add_option(BROADCAST_ADDRESS, 4, (uint8_t*)&addr);
}

bool Tins::DHCP::add_domain_name(const string &name) {
    return add_option(DOMAIN_NAME, name.size(), (const uint8_t*)name.c_str());
}

uint8_t *Tins::DHCP::serialize_list(const list<uint32_t> &int_list, uint32_t &sz) {
    uint8_t *buffer = new uint8_t[int_list.size() * sizeof(uint32_t)];
    uint32_t *ptr = (uint32_t*)buffer;
    for(list<uint32_t>::const_iterator it = int_list.begin(); it != int_list.end(); ++it)
        *(ptr++) = *it;
    sz = sizeof(uint32_t) * int_list.size();
    return buffer;
}

uint32_t Tins::DHCP::header_size() const {
    return BootP::header_size() - vend_size() + _size;
}

void Tins::DHCP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent) {
    assert(total_sz >= header_size());
    uint8_t *result = 0;
    if(_size) {
        result = new uint8_t[_size];
        uint8_t *ptr = result + sizeof(uint32_t);
        // Magic cookie
        *((uint32_t*)result) = Utils::net_to_host_l(0x63825363);
        for(std::list<DHCPOption>::const_iterator it = _options.begin(); it != _options.end(); ++it) {
            *(ptr++) = it->option;
            *(ptr++) = it->length;
            std::memcpy(ptr, it->value, it->length);
            ptr += it->length;
        }
        // End of options
        result[_size-1] = END;
        vend(result, _size);
    }
    BootP::write_serialization(buffer, total_sz, parent);
    delete[] result;
}

<|endoftext|>


<commit_before>#include <map>

#include "assert.hpp"

#include "TimingGraph.hpp"

NodeId TimingGraph::add_node(const TN_Type type, const DomainId clock_domain, const bool is_clk_src) {
    //Type
    node_types_.push_back(type);

    //Domain
    node_clock_domains_.push_back(clock_domain);

    //Clock source
    node_is_clock_source_.push_back(is_clk_src);

    //Edges
    node_out_edges_.push_back(std::vector<EdgeId>());
    node_in_edges_.push_back(std::vector<EdgeId>());

    NodeId node_id = node_types_.size() - 1;

    //Verify sizes
    ASSERT(node_types_.size() == node_clock_domains_.size());
    ASSERT(node_types_.size() == node_is_clock_source_.size());

    //Return the ID of the added node
    return node_id;
}

EdgeId TimingGraph::add_edge(const NodeId src_node, const NodeId sink_node) {
    //We require that the source/sink node must already be in the graph,
    //  so we can update them with thier edge references
    VERIFY(src_node < num_nodes());
    VERIFY(sink_node < num_nodes());

    //Create the edgge
    edge_src_nodes_.push_back(src_node);
    edge_sink_nodes_.push_back(sink_node);

    //Verify
    ASSERT(edge_sink_nodes_.size() == edge_src_nodes_.size());

    //The id of the new edge
    EdgeId edge_id = edge_sink_nodes_.size() - 1;

    //Update the nodes the edge references
    node_out_edges_[src_node].push_back(edge_id);
    node_in_edges_[sink_node].push_back(edge_id);

    //Return the edge id of the added edge
    return edge_id;
}

void TimingGraph::levelize() {
    //Levelizes the timing graph
    //This over-writes any previous levelization if it exists.
    //
    //Also records primary outputs

    //Clear any previous levelization
    node_levels_.clear();
    primary_outputs_.clear();

    //Allocate space for the first level
    node_levels_.resize(1);

    //Copy the number of input edges per-node
    //These will be decremented to know when all a node's upstream parents have been
    //placed in a previous level (indicating that the node goes in the current level)
    //
    //Also initialize the first level (nodes with no fanin)
    std::vector<int> node_fanin_remaining(num_nodes());
    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        int node_fanin = num_node_in_edges(node_id);
        node_fanin_remaining[node_id] = node_fanin;

        if(node_fanin == 0) {
            //Add a primary input
            node_levels_[0].push_back(node_id);
        }
    }

    //Walk the graph from primary inputs (no fanin) to generate a topological sort
    //
    //We inspect the output edges of each node and decrement the fanin count of the
    //target node.  Once the fanin count for a node reaches zero it can be added
    //to the current level.
    int level_id = 0;
    bool inserted_node_in_level = true;
    while(inserted_node_in_level) { //If nothing was inserted we are finished
        inserted_node_in_level = false;

        for(const NodeId node_id : node_levels_[level_id]) {
            //Inspect the fanout
            for(int edge_idx = 0; edge_idx < num_node_out_edges(node_id); edge_idx++) {
                EdgeId edge_id = node_out_edge(node_id, edge_idx);
                NodeId sink_node = edge_sink_node(edge_id);

                //Decrement the fanin count
                VERIFY(node_fanin_remaining[sink_node] > 0);
                node_fanin_remaining[sink_node]--;

                //Add to the next level if all fanin has been seen
                if(node_fanin_remaining[sink_node] == 0) {
                    //Ensure there is space by allocating the next level if required
                    node_levels_.resize(level_id+2);

                    //Add the node
                    node_levels_[level_id+1].push_back(sink_node);

                    inserted_node_in_level = true;
                }
            }

            //Also track the primary outputs
            if(num_node_out_edges(node_id) == 0) {
                primary_outputs_.push_back(node_id);
            }
        }
        level_id++;
    }
}

std::vector<EdgeId> TimingGraph::optimize_edge_layout() {
    //Make all edges in a level be contiguous in memory
    std::cout << "Re-allocating edges so levels are in contiguous memory" << std::endl;

    //Determine the edges driven by each level of the graph
    std::vector<std::vector<EdgeId>> edge_levels;
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        edge_levels.push_back(std::vector<EdgeId>());
        for(auto node_id : node_levels_[level_idx]) {
            for(int i = 0; i < num_node_out_edges(node_id); i++) {
                EdgeId edge_id = node_out_edge(node_id, i);

                //edge_id is driven by nodes in level level_idx
                edge_levels[level_idx].push_back(edge_id);
            }
        }
    }

    /*
     * Determine the new index for each edge in the graph
     * by walking through the edges in levelized order
     */
    /*
     *
     * //Maps from from original to new edge id, used to update node's edge refs
     *std::vector<EdgeId> orig_to_new_edge_id = std::vector<NodeId>(num_edges(), -1);
     *int cnt = 0;
     *for(std::vector<EdgeId>& edge_level : edge_levels) {
     *    for(EdgeId orig_edge_id : edge_level) {
     *        orig_to_new_edge_id[orig_edge_id] = cnt;
     *        cnt++;
     *    }
     *}
     */

    /*
     * Re-allocate edges to be contiguous in memory
     */

    //Maps from from original to new edge id, used to update node to edge refs
    std::vector<EdgeId> orig_to_new_edge_id(num_edges(), -1);

    //Save the old values while we write the new ones
    std::vector<NodeId> old_edge_sink_nodes_;
    std::vector<NodeId> old_edge_src_nodes_;

    //Swap them
    std::swap(old_edge_sink_nodes_, edge_sink_nodes_);
    std::swap(old_edge_src_nodes_, edge_src_nodes_);

    //Update edge to node refs
    for(auto& edge_level : edge_levels) {
        for(auto& orig_edge_id : edge_level) {
            //Write edges in the new contiguous order
            edge_sink_nodes_.push_back(old_edge_sink_nodes_[orig_edge_id]);
            edge_src_nodes_.push_back(old_edge_src_nodes_[orig_edge_id]);

            //Save the new edge id to update nodes
            orig_to_new_edge_id[orig_edge_id] = edge_sink_nodes_.size() - 1;
        }
    }

    //Update node to edge refs
    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        for(int edge_idx = 0; edge_idx < num_node_out_edges(node_id); edge_idx++) {
            EdgeId old_edge_id = node_out_edges_[node_id][edge_idx];
            EdgeId new_edge_id = orig_to_new_edge_id[old_edge_id];
            node_out_edges_[node_id][edge_idx] = new_edge_id;
        }
        for(int edge_idx = 0; edge_idx < num_node_in_edges(node_id); edge_idx++) {
            EdgeId old_edge_id = node_in_edges_[node_id][edge_idx];
            EdgeId new_edge_id = orig_to_new_edge_id[old_edge_id];
            node_in_edges_[node_id][edge_idx] = new_edge_id;
        }
    }

    return orig_to_new_edge_id;
}

std::vector<NodeId> TimingGraph::optimize_node_layout() {
    //Make all nodes in a level be contiguous in memory
    std::cout << "Re-allocating nodes so levels are in contiguous memory" << std::endl;

    /*
     * Build a map of the old and new node ids to update edges
     * and node levels later
     */
    std::vector<NodeId> orig_node_id_map = std::vector<NodeId>(num_nodes(), -1);
    int cnt = 0;
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(NodeId node_id : node_levels_[level_idx]) {
            orig_node_id_map[node_id] = cnt;
            cnt++;
        }
    }

    /*
     * Re-allocate nodes so levels are in contiguous memory
     */
    std::vector<TN_Type> old_node_types;
    std::vector<DomainId> old_node_clock_domains;
    std::vector<std::vector<EdgeId>> old_node_out_edges;
    std::vector<std::vector<EdgeId>> old_node_in_edges;
    std::vector<bool> old_node_is_clock_source;

    //Swap the values
    std::swap(old_node_types, node_types_);
    std::swap(old_node_clock_domains, node_clock_domains_);
    std::swap(old_node_out_edges, node_out_edges_);
    std::swap(old_node_in_edges, node_in_edges_);
    std::swap(old_node_is_clock_source, node_is_clock_source_);

    //Update the values
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(NodeId old_node_id : node_levels_[level_idx]) {
            node_types_.push_back(old_node_types[old_node_id]);
            node_clock_domains_.push_back(old_node_clock_domains[old_node_id]);
            node_out_edges_.push_back(old_node_out_edges[old_node_id]);
            node_in_edges_.push_back(old_node_in_edges[old_node_id]);
            node_is_clock_source_.push_back(old_node_is_clock_source[old_node_id]);
        }
    }

    /*
     * Update old references to node_ids with thier new values
     */
    //The node levels
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(size_t i = 0; i < node_levels_[level_idx].size(); i++) {
            NodeId old_node_id = node_levels_[level_idx][i];
            node_levels_[level_idx][i] = orig_node_id_map[old_node_id];
        }
    }

    //The primary outputs
    for(size_t i = 0; i < primary_outputs_.size(); i++) {
        NodeId old_node_id = primary_outputs_[i];
        primary_outputs_[i] = orig_node_id_map[old_node_id];
    }

    //The Edges
    for(int i = 0; i < num_edges(); i++) {
        NodeId old_sink_node = edge_sink_nodes_[i];
        NodeId old_src_node = edge_src_nodes_[i];

        edge_sink_nodes_[i] = orig_node_id_map[old_sink_node];
        edge_src_nodes_[i] = orig_node_id_map[old_src_node];
    }

    return orig_node_id_map;
}

//Stream extraction for TN_Type
std::istream& operator>>(std::istream& is, TN_Type& type) {
    std::string tok;
    is >> tok; //Read in a token
    if(tok == "INPAD_SOURCE")               type = TN_Type::INPAD_SOURCE;
    else if (tok == "INPAD_OPIN")           type = TN_Type::INPAD_OPIN;
    else if (tok == "OUTPAD_IPIN")          type = TN_Type::OUTPAD_IPIN;
    else if (tok == "OUTPAD_SINK")          type = TN_Type::OUTPAD_SINK;
    else if (tok == "PRIMITIVE_IPIN")       type = TN_Type::PRIMITIVE_IPIN;
    else if (tok == "PRIMITIVE_OPIN")       type = TN_Type::PRIMITIVE_OPIN;
    else if (tok == "FF_IPIN")              type = TN_Type::FF_IPIN;
    else if (tok == "FF_OPIN")              type = TN_Type::FF_OPIN;
    else if (tok == "FF_SINK")              type = TN_Type::FF_SINK;
    else if (tok == "FF_SOURCE")            type = TN_Type::FF_SOURCE;
    else if (tok == "FF_CLOCK")             type = TN_Type::FF_CLOCK;
    else if (tok == "CLOCK_SOURCE")         type = TN_Type::CLOCK_SOURCE;
    else if (tok == "CLOCK_OPIN")           type = TN_Type::CLOCK_OPIN;
    else if (tok == "CONSTANT_GEN_SOURCE")  type = TN_Type::CONSTANT_GEN_SOURCE;
    else if (tok == "UNKOWN")               type = TN_Type::UNKOWN;
    else throw std::domain_error(std::string("Unrecognized TN_Type: ") + tok);
    return is;
}

//Stream output for TN_Type
std::ostream& operator<<(std::ostream& os, const TN_Type type) {
    if(type == TN_Type::INPAD_SOURCE)              os << "INPAD_SOURCE";
    else if (type == TN_Type::INPAD_OPIN)          os << "INPAD_OPIN";
    else if (type == TN_Type::OUTPAD_IPIN)         os << "OUTPAD_IPIN";
    else if (type == TN_Type::OUTPAD_SINK)         os << "OUTPAD_SINK";
    else if (type == TN_Type::PRIMITIVE_IPIN)      os << "PRIMITIVE_IPIN";
    else if (type == TN_Type::PRIMITIVE_OPIN)      os << "PRIMITIVE_OPIN";
    else if (type == TN_Type::FF_IPIN)             os << "FF_IPIN";
    else if (type == TN_Type::FF_OPIN)             os << "FF_OPIN";
    else if (type == TN_Type::FF_SINK)             os << "FF_SINK";
    else if (type == TN_Type::FF_SOURCE)           os << "FF_SOURCE";
    else if (type == TN_Type::FF_CLOCK)            os << "FF_CLOCK";
    else if (type == TN_Type::CLOCK_SOURCE)        os << "CLOCK_SOURCE";
    else if (type == TN_Type::CLOCK_OPIN)          os << "CLOCK_OPIN";
    else if (type == TN_Type::CONSTANT_GEN_SOURCE) os << "CONSTANT_GEN_SOURCE";
    else if (type == TN_Type::UNKOWN)              os << "UNKOWN";
    else throw std::domain_error("Unrecognized TN_Type");
    return os;
}

<commit_msg>Improve node re-ordering code clarity and comments.<commit_after>#include <map>

#include "assert.hpp"

#include "TimingGraph.hpp"

NodeId TimingGraph::add_node(const TN_Type type, const DomainId clock_domain, const bool is_clk_src) {
    //Type
    node_types_.push_back(type);

    //Domain
    node_clock_domains_.push_back(clock_domain);

    //Clock source
    node_is_clock_source_.push_back(is_clk_src);

    //Edges
    node_out_edges_.push_back(std::vector<EdgeId>());
    node_in_edges_.push_back(std::vector<EdgeId>());

    NodeId node_id = node_types_.size() - 1;

    //Verify sizes
    ASSERT(node_types_.size() == node_clock_domains_.size());
    ASSERT(node_types_.size() == node_is_clock_source_.size());

    //Return the ID of the added node
    return node_id;
}

EdgeId TimingGraph::add_edge(const NodeId src_node, const NodeId sink_node) {
    //We require that the source/sink node must already be in the graph,
    //  so we can update them with thier edge references
    VERIFY(src_node < num_nodes());
    VERIFY(sink_node < num_nodes());

    //Create the edgge
    edge_src_nodes_.push_back(src_node);
    edge_sink_nodes_.push_back(sink_node);

    //Verify
    ASSERT(edge_sink_nodes_.size() == edge_src_nodes_.size());

    //The id of the new edge
    EdgeId edge_id = edge_sink_nodes_.size() - 1;

    //Update the nodes the edge references
    node_out_edges_[src_node].push_back(edge_id);
    node_in_edges_[sink_node].push_back(edge_id);

    //Return the edge id of the added edge
    return edge_id;
}

void TimingGraph::levelize() {
    //Levelizes the timing graph
    //This over-writes any previous levelization if it exists.
    //
    //Also records primary outputs

    //Clear any previous levelization
    node_levels_.clear();
    primary_outputs_.clear();

    //Allocate space for the first level
    node_levels_.resize(1);

    //Copy the number of input edges per-node
    //These will be decremented to know when all a node's upstream parents have been
    //placed in a previous level (indicating that the node goes in the current level)
    //
    //Also initialize the first level (nodes with no fanin)
    std::vector<int> node_fanin_remaining(num_nodes());
    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        int node_fanin = num_node_in_edges(node_id);
        node_fanin_remaining[node_id] = node_fanin;

        if(node_fanin == 0) {
            //Add a primary input
            node_levels_[0].push_back(node_id);
        }
    }

    //Walk the graph from primary inputs (no fanin) to generate a topological sort
    //
    //We inspect the output edges of each node and decrement the fanin count of the
    //target node.  Once the fanin count for a node reaches zero it can be added
    //to the current level.
    int level_id = 0;
    bool inserted_node_in_level = true;
    while(inserted_node_in_level) { //If nothing was inserted we are finished
        inserted_node_in_level = false;

        for(const NodeId node_id : node_levels_[level_id]) {
            //Inspect the fanout
            for(int edge_idx = 0; edge_idx < num_node_out_edges(node_id); edge_idx++) {
                EdgeId edge_id = node_out_edge(node_id, edge_idx);
                NodeId sink_node = edge_sink_node(edge_id);

                //Decrement the fanin count
                VERIFY(node_fanin_remaining[sink_node] > 0);
                node_fanin_remaining[sink_node]--;

                //Add to the next level if all fanin has been seen
                if(node_fanin_remaining[sink_node] == 0) {
                    //Ensure there is space by allocating the next level if required
                    node_levels_.resize(level_id+2);

                    //Add the node
                    node_levels_[level_id+1].push_back(sink_node);

                    inserted_node_in_level = true;
                }
            }

            //Also track the primary outputs
            if(num_node_out_edges(node_id) == 0) {
                primary_outputs_.push_back(node_id);
            }
        }
        level_id++;
    }
}

std::vector<EdgeId> TimingGraph::optimize_edge_layout() {
    //Make all edges in a level be contiguous in memory
    std::cout << "Re-allocating edges so levels are in contiguous memory" << std::endl;

    //Determine the edges driven by each level of the graph
    std::vector<std::vector<EdgeId>> edge_levels;
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        edge_levels.push_back(std::vector<EdgeId>());
        for(auto node_id : node_levels_[level_idx]) {
            for(int i = 0; i < num_node_out_edges(node_id); i++) {
                EdgeId edge_id = node_out_edge(node_id, i);

                //edge_id is driven by nodes in level level_idx
                edge_levels[level_idx].push_back(edge_id);
            }
        }
    }

    /*
     * Determine the new index for each edge in the graph
     * by walking through the edges in levelized order
     */
    /*
     *
     * //Maps from from original to new edge id, used to update node's edge refs
     *std::vector<EdgeId> orig_to_new_edge_id = std::vector<NodeId>(num_edges(), -1);
     *int cnt = 0;
     *for(std::vector<EdgeId>& edge_level : edge_levels) {
     *    for(EdgeId orig_edge_id : edge_level) {
     *        orig_to_new_edge_id[orig_edge_id] = cnt;
     *        cnt++;
     *    }
     *}
     */

    /*
     * Re-allocate edges to be contiguous in memory
     */

    //Maps from from original to new edge id, used to update node to edge refs
    std::vector<EdgeId> orig_to_new_edge_id(num_edges(), -1);

    //Save the old values while we write the new ones
    std::vector<NodeId> old_edge_sink_nodes_;
    std::vector<NodeId> old_edge_src_nodes_;

    //Swap them
    std::swap(old_edge_sink_nodes_, edge_sink_nodes_);
    std::swap(old_edge_src_nodes_, edge_src_nodes_);

    //Update edge to node refs
    for(auto& edge_level : edge_levels) {
        for(auto& orig_edge_id : edge_level) {
            //Write edges in the new contiguous order
            edge_sink_nodes_.push_back(old_edge_sink_nodes_[orig_edge_id]);
            edge_src_nodes_.push_back(old_edge_src_nodes_[orig_edge_id]);

            //Save the new edge id to update nodes
            orig_to_new_edge_id[orig_edge_id] = edge_sink_nodes_.size() - 1;
        }
    }

    //Update node to edge refs
    for(NodeId node_id = 0; node_id < num_nodes(); node_id++) {
        for(int edge_idx = 0; edge_idx < num_node_out_edges(node_id); edge_idx++) {
            EdgeId old_edge_id = node_out_edges_[node_id][edge_idx];
            EdgeId new_edge_id = orig_to_new_edge_id[old_edge_id];
            node_out_edges_[node_id][edge_idx] = new_edge_id;
        }
        for(int edge_idx = 0; edge_idx < num_node_in_edges(node_id); edge_idx++) {
            EdgeId old_edge_id = node_in_edges_[node_id][edge_idx];
            EdgeId new_edge_id = orig_to_new_edge_id[old_edge_id];
            node_in_edges_[node_id][edge_idx] = new_edge_id;
        }
    }

    return orig_to_new_edge_id;
}

std::vector<NodeId> TimingGraph::optimize_node_layout() {
    //Make all nodes in a level be contiguous in memory
    std::cout << "Re-allocating nodes so levels are in contiguous memory" << std::endl;

    /*
     * Keep a map of the old and new node ids to update edges
     * and node levels later
     */
    std::vector<NodeId> orig_to_new_node_id = std::vector<NodeId>(num_nodes(), -1);
    /*
     *int cnt = 0;
     *for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
     *    for(NodeId node_id : node_levels_[level_idx]) {
     *        orig_to_new_node_id[node_id] = cnt;
     *        cnt++;
     *    }
     *}
     */

    /*
     * Re-allocate nodes so levels are in contiguous memory
     */
    std::vector<TN_Type> old_node_types;
    std::vector<DomainId> old_node_clock_domains;
    std::vector<std::vector<EdgeId>> old_node_out_edges;
    std::vector<std::vector<EdgeId>> old_node_in_edges;
    std::vector<bool> old_node_is_clock_source;

    //Swap the values
    std::swap(old_node_types, node_types_);
    std::swap(old_node_clock_domains, node_clock_domains_);
    std::swap(old_node_out_edges, node_out_edges_);
    std::swap(old_node_in_edges, node_in_edges_);
    std::swap(old_node_is_clock_source, node_is_clock_source_);

    //Update the values
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(NodeId old_node_id : node_levels_[level_idx]) {
            node_types_.push_back(old_node_types[old_node_id]);
            node_clock_domains_.push_back(old_node_clock_domains[old_node_id]);
            node_out_edges_.push_back(old_node_out_edges[old_node_id]);
            node_in_edges_.push_back(old_node_in_edges[old_node_id]);
            node_is_clock_source_.push_back(old_node_is_clock_source[old_node_id]);

            //Record the new node id
            orig_to_new_node_id[old_node_id] = node_types_.size() - 1;
        }
    }

    /*
     * Update old references to node_ids with thier new values
     */
    //The node levels
    for(int level_idx = 0; level_idx < num_levels(); level_idx++) {
        for(size_t node_idx = 0; node_idx < node_levels_[level_idx].size(); node_idx++) {
            NodeId old_node_id = node_levels_[level_idx][node_idx];
            NodeId new_node_id = orig_to_new_node_id[old_node_id];

            node_levels_[level_idx][node_idx] = new_node_id;
        }
    }

    //The primary outputs
    for(size_t i = 0; i < primary_outputs_.size(); i++) {
        NodeId old_node_id = primary_outputs_[i];
        NodeId new_node_id = orig_to_new_node_id[old_node_id];

        primary_outputs_[i] = new_node_id;
    }

    //The Edges
    for(int i = 0; i < num_edges(); i++) {
        NodeId old_sink_node = edge_sink_nodes_[i];
        NodeId old_src_node = edge_src_nodes_[i];

        NodeId new_sink_node = orig_to_new_node_id[old_sink_node];
        NodeId new_src_node = orig_to_new_node_id[old_src_node];

        edge_sink_nodes_[i] = new_sink_node;
        edge_src_nodes_[i] = new_src_node;
    }

    return orig_to_new_node_id;
}

//Stream extraction for TN_Type
std::istream& operator>>(std::istream& is, TN_Type& type) {
    std::string tok;
    is >> tok; //Read in a token
    if(tok == "INPAD_SOURCE")               type = TN_Type::INPAD_SOURCE;
    else if (tok == "INPAD_OPIN")           type = TN_Type::INPAD_OPIN;
    else if (tok == "OUTPAD_IPIN")          type = TN_Type::OUTPAD_IPIN;
    else if (tok == "OUTPAD_SINK")          type = TN_Type::OUTPAD_SINK;
    else if (tok == "PRIMITIVE_IPIN")       type = TN_Type::PRIMITIVE_IPIN;
    else if (tok == "PRIMITIVE_OPIN")       type = TN_Type::PRIMITIVE_OPIN;
    else if (tok == "FF_IPIN")              type = TN_Type::FF_IPIN;
    else if (tok == "FF_OPIN")              type = TN_Type::FF_OPIN;
    else if (tok == "FF_SINK")              type = TN_Type::FF_SINK;
    else if (tok == "FF_SOURCE")            type = TN_Type::FF_SOURCE;
    else if (tok == "FF_CLOCK")             type = TN_Type::FF_CLOCK;
    else if (tok == "CLOCK_SOURCE")         type = TN_Type::CLOCK_SOURCE;
    else if (tok == "CLOCK_OPIN")           type = TN_Type::CLOCK_OPIN;
    else if (tok == "CONSTANT_GEN_SOURCE")  type = TN_Type::CONSTANT_GEN_SOURCE;
    else if (tok == "UNKOWN")               type = TN_Type::UNKOWN;
    else throw std::domain_error(std::string("Unrecognized TN_Type: ") + tok);
    return is;
}

//Stream output for TN_Type
std::ostream& operator<<(std::ostream& os, const TN_Type type) {
    if(type == TN_Type::INPAD_SOURCE)              os << "INPAD_SOURCE";
    else if (type == TN_Type::INPAD_OPIN)          os << "INPAD_OPIN";
    else if (type == TN_Type::OUTPAD_IPIN)         os << "OUTPAD_IPIN";
    else if (type == TN_Type::OUTPAD_SINK)         os << "OUTPAD_SINK";
    else if (type == TN_Type::PRIMITIVE_IPIN)      os << "PRIMITIVE_IPIN";
    else if (type == TN_Type::PRIMITIVE_OPIN)      os << "PRIMITIVE_OPIN";
    else if (type == TN_Type::FF_IPIN)             os << "FF_IPIN";
    else if (type == TN_Type::FF_OPIN)             os << "FF_OPIN";
    else if (type == TN_Type::FF_SINK)             os << "FF_SINK";
    else if (type == TN_Type::FF_SOURCE)           os << "FF_SOURCE";
    else if (type == TN_Type::FF_CLOCK)            os << "FF_CLOCK";
    else if (type == TN_Type::CLOCK_SOURCE)        os << "CLOCK_SOURCE";
    else if (type == TN_Type::CLOCK_OPIN)          os << "CLOCK_OPIN";
    else if (type == TN_Type::CONSTANT_GEN_SOURCE) os << "CONSTANT_GEN_SOURCE";
    else if (type == TN_Type::UNKOWN)              os << "UNKOWN";
    else throw std::domain_error("Unrecognized TN_Type");
    return os;
}

<|endoftext|>


<commit_before>#include "dp.h"

#include <memory>

DynamicParallelism::DynamicParallelism()
{
	runtime  = clRuntime::getInstance();
	file     = clFile::getInstance();

	platform = runtime->getPlatformID();
	device   = runtime->getDevice();
	context  = runtime->getContext();
	cmdQueue = runtime->getCmdQueue(0);

	glbSize = 8192;
	locSize = 256;
	factor  = 2.3f;

	init();
}

DynamicParallelism::~DynamicParallelism()
{
	clean();
}

void DynamicParallelism::init()
{
	initKernel();
	initBuffer();
}

void DynamicParallelism::initKernel()
{
	cl_int err;

	// Open kernel file
        file->open("dp_Kernels.cl");

        // Create program
        const char *source = file->getSourceChar();
        program = clCreateProgramWithSource(context, 1,
                (const char **)&source, NULL, &err);
        checkOpenCLErrors(err, "Failed to create Program with source\n");

        // Create program with OpenCL 2.0 support
        err = clBuildProgram(program, 0, NULL, "-I. -cl-std=CL2.0", NULL, NULL);
        checkOpenCLErrors(err, "Failed to build program...\n");

        // Create kernels
        kernel_saxpy_naive = clCreateKernel(program, "saxpy_naive", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_naive kernel");
        kernel_saxpy_stride = clCreateKernel(program, "saxpy_stride", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_stride kernel");
        kernel_saxpy_dp = clCreateKernel(program, "saxpy_dp", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_dp kernel");
}

void DynamicParallelism::initBuffer()
{
	cl_int err;
	size_t glbSizeBytes = glbSize * sizeof(float);

	saxpy_src_0 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_src_1 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_dst_0 = (float *)clSVMAlloc(context, CL_MEM_READ_WRITE, glbSizeBytes, 0);

	float two = 2.0f;
	float three = 3.0f;

	err  = clEnqueueSVMMemFill(cmdQueue, saxpy_src_0, (const void *)&two, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	err |= clEnqueueSVMMemFill(cmdQueue, saxpy_src_1, (const void *)&three, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to fill SVM buffers");

	err = clFlush(cmdQueue);
	checkOpenCLErrors(err, "Failed to clFlush cmdQueue");

}

void DynamicParallelism::clean()
{
	cleanKernel();
	cleanBuffer();
}

void DynamicParallelism::cleanKernel()
{
	cl_int err;

	err = clReleaseKernel(kernel_saxpy_naive);
	err |= clReleaseKernel(kernel_saxpy_stride);
	err |= clReleaseKernel(kernel_saxpy_dp);
	checkOpenCLErrors(err, "Failed to release kernels");

	err = clReleaseProgram(program);
	checkOpenCLErrors(err, "Failed to release program");
}

void DynamicParallelism::cleanBuffer()
{
	clSVMFreeSafe(context, saxpy_src_0);
	clSVMFreeSafe(context, saxpy_src_1);
	clSVMFreeSafe(context, saxpy_dst_0);
}

void DynamicParallelism::runNaive()
{
	cl_int err;

	size_t globalSize[1] = {(size_t)glbSize};
	size_t localSize[1]  = {(size_t)locSize};

	err  = clSetKernelArg(kernel_saxpy_naive, 0, sizeof(int), (void *)&glbSize);
	err |= clSetKernelArg(kernel_saxpy_naive, 1, sizeof(int), (void *)&factor);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 2, saxpy_src_0);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 3, saxpy_src_1);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 4, saxpy_dst_0);
	checkOpenCLErrors(err, "Failed to set args in saxpy_naive kernel");

        err = clEnqueueNDRangeKernel(
                cmdQueue,
                kernel_saxpy_naive,
                1,
                0, globalSize, localSize,
                0, 0, 0
        );
        checkOpenCLErrors(err, "Failed at clEnqueueNDRangeKernel");

	// Map SVM buffers
	size_t glbSizeBytes = glbSize * sizeof(float);
	err  = clEnqueueSVMMap(cmdQueue, CL_TRUE, CL_MEM_READ_ONLY, saxpy_dst_0, glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to map SVM buffers for checking result");

	// Check result
	for (int i = 0; i < glbSize / locSize; ++i)
		printf("%f\n", saxpy_dst_0[i]);

	// Unmap SVM buffers
	err  = clEnqueueSVMUnmap(cmdQueue, saxpy_dst_0, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to unmap SVM buffers after checking result");

}

void DynamicParallelism::runStride()
{

}

void DynamicParallelism::runDP()
{

}
int main(int argc, char const *argv[])
{
	std::unique_ptr<DynamicParallelism> dp(new DynamicParallelism());

	printf("Running...\n");

	dp->runNaive();
	dp->runStride();
	dp->runDP();

	printf("Done!\n");

	return 0;
}<commit_msg>Update<commit_after>#include "dp.h"

#include <memory>

DynamicParallelism::DynamicParallelism()
{
	runtime  = clRuntime::getInstance();
	file     = clFile::getInstance();

	platform = runtime->getPlatformID();
	device   = runtime->getDevice();
	context  = runtime->getContext();
	cmdQueue = runtime->getCmdQueue(0);

	glbSize = 8192;
	locSize = 256;
	factor  = 2.3f;

	init();
}

DynamicParallelism::~DynamicParallelism()
{
	clean();
}

void DynamicParallelism::init()
{
	initKernel();
	initBuffer();
}

void DynamicParallelism::initKernel()
{
	cl_int err;

	// Open kernel file
        file->open("dp_Kernels.cl");

        // Create program
        const char *source = file->getSourceChar();
        program = clCreateProgramWithSource(context, 1,
                (const char **)&source, NULL, &err);
        checkOpenCLErrors(err, "Failed to create Program with source\n");

        // Create program with OpenCL 2.0 support
        err = clBuildProgram(program, 0, NULL, "-I. -cl-std=CL2.0", NULL, NULL);
        checkOpenCLErrors(err, "Failed to build program...\n");

        // Create kernels
        kernel_saxpy_naive = clCreateKernel(program, "saxpy_naive", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_naive kernel");
        kernel_saxpy_stride = clCreateKernel(program, "saxpy_stride", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_stride kernel");
        kernel_saxpy_dp = clCreateKernel(program, "saxpy_dp", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_dp kernel");
}

void DynamicParallelism::initBuffer()
{
	cl_int err;
	size_t glbSizeBytes = glbSize * sizeof(float);

	saxpy_src_0 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_src_1 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_dst_0 = (float *)clSVMAlloc(context, CL_MEM_READ_WRITE, glbSizeBytes, 0);

	float one = 1.0f;
	float two = 2.0f;
	float three = 3.0f;

	err  = clEnqueueSVMMemFill(cmdQueue, saxpy_src_0, (const void *)&one, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	err  = clEnqueueSVMMemFill(cmdQueue, saxpy_src_1, (const void *)&two, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	err |= clEnqueueSVMMemFill(cmdQueue, saxpy_dst_0, (const void *)&three, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to fill SVM buffers");

	err = clFlush(cmdQueue);
	checkOpenCLErrors(err, "Failed to clFlush cmdQueue");

}

void DynamicParallelism::clean()
{
	cleanKernel();
	cleanBuffer();
}

void DynamicParallelism::cleanKernel()
{
	cl_int err;

	err = clReleaseKernel(kernel_saxpy_naive);
	err |= clReleaseKernel(kernel_saxpy_stride);
	err |= clReleaseKernel(kernel_saxpy_dp);
	checkOpenCLErrors(err, "Failed to release kernels");

	err = clReleaseProgram(program);
	checkOpenCLErrors(err, "Failed to release program");
}

void DynamicParallelism::cleanBuffer()
{
	clSVMFreeSafe(context, saxpy_src_0);
	clSVMFreeSafe(context, saxpy_src_1);
	clSVMFreeSafe(context, saxpy_dst_0);
}

void DynamicParallelism::runNaive()
{
	cl_int err;

	size_t globalSize[1] = {(size_t)glbSize};
	size_t localSize[1]  = {(size_t)locSize};

	err  = clSetKernelArg(kernel_saxpy_naive, 0, sizeof(int), (void *)&glbSize);
	err |= clSetKernelArg(kernel_saxpy_naive, 1, sizeof(int), (void *)&factor);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 2, saxpy_src_0);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 3, saxpy_src_1);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 4, saxpy_dst_0);
	checkOpenCLErrors(err, "Failed to set args in saxpy_naive kernel");

        err = clEnqueueNDRangeKernel(
                cmdQueue,
                kernel_saxpy_naive,
                1,
                0, globalSize, localSize,
                0, 0, 0
        );
        checkOpenCLErrors(err, "Failed at clEnqueueNDRangeKernel");

	// Map SVM buffers
	size_t glbSizeBytes = glbSize * sizeof(float);
	err  = clEnqueueSVMMap(cmdQueue, CL_TRUE, CL_MEM_READ_ONLY, saxpy_dst_0, glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to map SVM buffers for checking result");

	// Check result
	for (int i = 0; i < glbSize / locSize; ++i)
		printf("%f\n", saxpy_dst_0[i]);

	// Unmap SVM buffers
	err  = clEnqueueSVMUnmap(cmdQueue, saxpy_dst_0, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to unmap SVM buffers after checking result");

}

void DynamicParallelism::runStride()
{

}

void DynamicParallelism::runDP()
{

}
int main(int argc, char const *argv[])
{
	std::unique_ptr<DynamicParallelism> dp(new DynamicParallelism());

	printf("Running...\n");

	dp->runNaive();
	dp->runStride();
	dp->runDP();

	printf("Done!\n");

	return 0;
}<|endoftext|>


<commit_before>#include "db.h"

#include "lpd8_sysex.h"
#include "utils.h"

#include <exception>

QString sqlErrorMessage(const QString& msg, const QSqlError& err) {
    return msg + QString("\n") + err.text();
}

bool isInitialized(const QSqlDatabase& db) {
    return db.tables().contains("programs");
}

QString programName(const QString& name = QString()) {
    return name.isEmpty() ? "default" : name;
}

#define GOTO_END_IF_FALSE(X) if (!X) goto end;

int createProgram(const QString &name, const QByteArray &sysex) {
    Q_UNUSED(name);
    Q_UNUSED(sysex);

    int programId = -1;

    QSqlDatabase::database().transaction();

    QSqlQuery q;
    GOTO_END_IF_FALSE(q.prepare("insert into programs default values;"));
    GOTO_END_IF_FALSE(q.exec());

    programId = q.lastInsertId().toInt();

    if (!name.isNull()) {
        GOTO_END_IF_FALSE(q.prepare("update programs set name = ? where programId = ?"));
        q.addBindValue(name);
        q.addBindValue(programId);
        GOTO_END_IF_FALSE(q.exec());
    }

    // XXX this is a lame check
    // Proper way would be to pass a QIODevice and register callbacks
    // ala SAX
    if (!sysex.isNull()) {
        QDataStream s(sysex);
        qint8 v = 0;

        // Header

        s >> v; // Sysex Start
        s >> v; // Manufacturer
        s >> v; // Model byte 1
        s >> v; // Model byte 2
        s >> v; // Opcode set program: byte1
        s >> v; // Opcode set program: byte2
        s >> v; // Opcode set program: byte3
        s >> v; // Program ID

        // Program

        s >> v;
        GOTO_END_IF_FALSE(q.prepare("update programs set channel = ? where programId = ?"));
        q.addBindValue(v);
        q.addBindValue(programId);
        GOTO_END_IF_FALSE(q.exec());

        // Pads

        for (int controlId = 0; controlId < sysex::padsCount(); ++controlId) {
            GOTO_END_IF_FALSE(q.prepare("update pads set note = ?, pc = ?, cc = ?, toggle = ? where programId = ? and controlId = ?"));
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            q.addBindValue(programId);
            q.addBindValue(controlId);
            GOTO_END_IF_FALSE(q.exec());
        }

        for (int controlId = 0; controlId < sysex::knobsCount(); ++controlId) {
            GOTO_END_IF_FALSE(q.prepare("update knobs set cc = ?, low = ?, high = ? where programId = ? and controlId = ?"));
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            q.addBindValue(programId);
            q.addBindValue(controlId);
            GOTO_END_IF_FALSE(q.exec());
        }
    }
end:
    if (q.lastError().isValid()) {
        qWarning() << "Failed to create program: " << q.lastError().text();
    }
    if (!QSqlDatabase::database().commit()) {
        qWarning() << "Failed to commit program creation transaction:" << QSqlDatabase::database().lastError().text();
    }
    return programId;
}

bool addProgram(const QString& name, int& programId) {
    QSqlQuery q;
    if (!q.prepare("insert into programs(name, channel) values(?, ?)")) return false;
    q.addBindValue(programName(name));
    q.addBindValue(10);
    if (!q.exec()) {
        return false;
    }
    programId = q.lastInsertId().toInt();
    return true;
}

bool addProgram(int programId) {
    QSqlQuery q;
    if (!q.prepare("insert into programs(programId, name, channel) values(?, ?, ?)")) return false;
    q.addBindValue(programId);
    q.addBindValue(programName());
    q.addBindValue(10);
    return q.exec();
}

bool deleteProgram(int programId) {
    Q_ASSERT(programId > 0);

    int count = 0;

    QSqlQuery q;
    GOTO_END_IF_FALSE(q.prepare("delete from programs where programId = ?"));
    q.addBindValue(programId);
    GOTO_END_IF_FALSE(q.exec());

    GOTO_END_IF_FALSE(q.prepare("select changes()"));
    GOTO_END_IF_FALSE(q.exec());
    if (!q.first()) {
        qWarning() << "Cannot get changes after deleting program" << programId;
        return false;
    }
    count = q.value(0).toInt();
    Q_ASSERT(count < 2);
    if (count == 0) {
        qWarning() << "Cannot delete inexistant program" << programId;
        return false;
    }

end:
    if (q.lastError().isValid()) {
        qWarning() << "Failed to delete program: " << q.lastError().text();
        return false;
    }
    return true;
}

bool programsIds(QList<int>& ids) {
    QSqlQuery q;
    if (!q.exec("select programId from programs;")) {
        qWarning() << "Cannot get programs IDs";
        qWarning() << q.lastError().text();
        return false;
    }

    ids.clear();
    // sqlite driver doesn't support query sizes
    while (q.next()) {
        ids.append(q.value(0).toInt());
    }
    return true;
}

int nextProgramId(int programId) {
    QList<int> ids;
    if (!programsIds(ids)) {
        return -1;
    }
    int i = ids.indexOf(programId);
    if (i == -1 || ids.count() == 1) {
        return -1;
    }
    if (i > 0) {
        return ids[i-1];
    }
    return ids[i+1];
}

bool setProgramName(int programId, const QString& name) {
    QSqlQuery q;
    if(!q.prepare("update programs set name = ? where programId = ?")) return false;
    q.addBindValue(name);
    q.addBindValue(programId);
    return q.exec();
}

bool isValidProgramId(int programId) {
    QList<int> ids;
    return programsIds(ids) ? ids.contains(programId) : false;
}

bool initialize() {
    QSqlQuery q;
    if (!q.exec(readTextFile(":/create_table_programs.sql"))) return false;
    if (!q.exec(readTextFile(":/create_table_pads.sql"))) return false;
    if (!q.exec(readTextFile(":/create_table_knobs.sql"))) return false;
    if (!q.exec(readTextFile(":/create_trigger_add_program.sql"))) return false;
    if (!q.exec(readTextFile(":/create_trigger_delete_program.sql"))) return false;
    return true;
}

QSqlError initDb(const QString& path) {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    QSqlDriver *driver = db.driver();

    Q_CHECK_PTR(driver);
    Q_ASSERT(driver->hasFeature(QSqlDriver::Transactions));
    Q_ASSERT(driver->hasFeature(QSqlDriver::Unicode));
    Q_ASSERT(driver->hasFeature(QSqlDriver::PreparedQueries));
    Q_ASSERT(driver->hasFeature(QSqlDriver::PositionalPlaceholders));
    Q_ASSERT(driver->hasFeature(QSqlDriver::LastInsertId));
    Q_ASSERT(driver->hasFeature(QSqlDriver::EventNotifications));

    db.setDatabaseName(path);

    if (!db.open()) {
        qWarning() << "Failed to open db" << path;
        goto end;
    }

    if (!isInitialized(db)) {
        if (!initialize()) {
            qWarning() << "Failed to initialize db" << path;
            goto end;
        }
    }

    end:
    return db.lastError();
}
<commit_msg>deleteProgram uses QSqlQuery::numRowsAfftected for its checks<commit_after>#include "db.h"

#include "lpd8_sysex.h"
#include "utils.h"

#include <exception>

QString sqlErrorMessage(const QString& msg, const QSqlError& err) {
    return msg + QString("\n") + err.text();
}

bool isInitialized(const QSqlDatabase& db) {
    return db.tables().contains("programs");
}

QString programName(const QString& name = QString()) {
    return name.isEmpty() ? "default" : name;
}

#define GOTO_END_IF_FALSE(X) if (!X) goto end;

int createProgram(const QString &name, const QByteArray &sysex) {
    Q_UNUSED(name);
    Q_UNUSED(sysex);

    int programId = -1;

    QSqlDatabase::database().transaction();

    QSqlQuery q;
    GOTO_END_IF_FALSE(q.prepare("insert into programs default values;"));
    GOTO_END_IF_FALSE(q.exec());

    programId = q.lastInsertId().toInt();

    if (!name.isNull()) {
        GOTO_END_IF_FALSE(q.prepare("update programs set name = ? where programId = ?"));
        q.addBindValue(name);
        q.addBindValue(programId);
        GOTO_END_IF_FALSE(q.exec());
    }

    // XXX this is a lame check
    // Proper way would be to pass a QIODevice and register callbacks
    // ala SAX
    if (!sysex.isNull()) {
        QDataStream s(sysex);
        qint8 v = 0;

        // Header

        s >> v; // Sysex Start
        s >> v; // Manufacturer
        s >> v; // Model byte 1
        s >> v; // Model byte 2
        s >> v; // Opcode set program: byte1
        s >> v; // Opcode set program: byte2
        s >> v; // Opcode set program: byte3
        s >> v; // Program ID

        // Program

        s >> v;
        GOTO_END_IF_FALSE(q.prepare("update programs set channel = ? where programId = ?"));
        q.addBindValue(v);
        q.addBindValue(programId);
        GOTO_END_IF_FALSE(q.exec());

        // Pads

        for (int controlId = 0; controlId < sysex::padsCount(); ++controlId) {
            GOTO_END_IF_FALSE(q.prepare("update pads set note = ?, pc = ?, cc = ?, toggle = ? where programId = ? and controlId = ?"));
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            q.addBindValue(programId);
            q.addBindValue(controlId);
            GOTO_END_IF_FALSE(q.exec());
        }

        for (int controlId = 0; controlId < sysex::knobsCount(); ++controlId) {
            GOTO_END_IF_FALSE(q.prepare("update knobs set cc = ?, low = ?, high = ? where programId = ? and controlId = ?"));
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            s >> v;
            q.addBindValue(v);
            q.addBindValue(programId);
            q.addBindValue(controlId);
            GOTO_END_IF_FALSE(q.exec());
        }
    }
end:
    if (q.lastError().isValid()) {
        qWarning() << "Failed to create program: " << q.lastError().text();
    }
    if (!QSqlDatabase::database().commit()) {
        qWarning() << "Failed to commit program creation transaction:" << QSqlDatabase::database().lastError().text();
    }
    return programId;
}

bool addProgram(const QString& name, int& programId) {
    QSqlQuery q;
    if (!q.prepare("insert into programs(name, channel) values(?, ?)")) return false;
    q.addBindValue(programName(name));
    q.addBindValue(10);
    if (!q.exec()) {
        return false;
    }
    programId = q.lastInsertId().toInt();
    return true;
}

bool addProgram(int programId) {
    QSqlQuery q;
    if (!q.prepare("insert into programs(programId, name, channel) values(?, ?, ?)")) return false;
    q.addBindValue(programId);
    q.addBindValue(programName());
    q.addBindValue(10);
    return q.exec();
}

bool deleteProgram(int programId) {
    QSqlQuery q;
    GOTO_END_IF_FALSE(q.prepare("delete from programs where programId = ?"));
    q.addBindValue(programId);
    GOTO_END_IF_FALSE(q.exec());

    Q_ASSERT(q.numRowsAffected() < 2);

    if (q.numRowsAffected() == 0) {
        qWarning() << "Cannot delete inexistant program" << programId;
        return false;
    }

end:
    if (q.lastError().isValid()) {
        qWarning() << "Failed to delete program: " << q.lastError().text();
        return false;
    }
    return true;
}

bool programsIds(QList<int>& ids) {
    QSqlQuery q;
    if (!q.exec("select programId from programs;")) {
        qWarning() << "Cannot get programs IDs";
        qWarning() << q.lastError().text();
        return false;
    }

    ids.clear();
    // sqlite driver doesn't support query sizes
    while (q.next()) {
        ids.append(q.value(0).toInt());
    }
    return true;
}

int nextProgramId(int programId) {
    QList<int> ids;
    if (!programsIds(ids)) {
        return -1;
    }
    int i = ids.indexOf(programId);
    if (i == -1 || ids.count() == 1) {
        return -1;
    }
    if (i > 0) {
        return ids[i-1];
    }
    return ids[i+1];
}

bool setProgramName(int programId, const QString& name) {
    QSqlQuery q;
    if(!q.prepare("update programs set name = ? where programId = ?")) return false;
    q.addBindValue(name);
    q.addBindValue(programId);
    return q.exec();
}

bool isValidProgramId(int programId) {
    QList<int> ids;
    return programsIds(ids) ? ids.contains(programId) : false;
}

bool initialize() {
    QSqlQuery q;
    if (!q.exec(readTextFile(":/create_table_programs.sql"))) return false;
    if (!q.exec(readTextFile(":/create_table_pads.sql"))) return false;
    if (!q.exec(readTextFile(":/create_table_knobs.sql"))) return false;
    if (!q.exec(readTextFile(":/create_trigger_add_program.sql"))) return false;
    if (!q.exec(readTextFile(":/create_trigger_delete_program.sql"))) return false;
    return true;
}

QSqlError initDb(const QString& path) {
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    QSqlDriver *driver = db.driver();

    Q_CHECK_PTR(driver);
    Q_ASSERT(driver->hasFeature(QSqlDriver::Transactions));
    Q_ASSERT(driver->hasFeature(QSqlDriver::Unicode));
    Q_ASSERT(driver->hasFeature(QSqlDriver::PreparedQueries));
    Q_ASSERT(driver->hasFeature(QSqlDriver::PositionalPlaceholders));
    Q_ASSERT(driver->hasFeature(QSqlDriver::LastInsertId));
    Q_ASSERT(driver->hasFeature(QSqlDriver::EventNotifications));

    db.setDatabaseName(path);

    if (!db.open()) {
        qWarning() << "Failed to open db" << path;
        goto end;
    }

    if (!isInitialized(db)) {
        if (!initialize()) {
            qWarning() << "Failed to initialize db" << path;
            goto end;
        }
    }

    end:
    return db.lastError();
}
<|endoftext|>