<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2016 - 2017)
//   Rene Milk       (2016 - 2017)

#ifndef DUNE_GDT_LOCAL_DOF_VECTOR_HH
#define DUNE_GDT_LOCAL_DOF_VECTOR_HH

#include <ostream>

#include <dune/xt/la/container/vector-interface.hh>

#include <dune/gdt/spaces/mapper/interfaces.hh>

namespace Dune {
namespace GDT {

template <class VectorImp>
class ConstLocalDoFVector
{
  static_assert(
      std::is_base_of<XT::LA::VectorInterface<typename VectorImp::Traits, typename VectorImp::Traits::ScalarType>,
                      VectorImp>::value,
      "VectorImp has to be derived from XT::LA::VectorInterface!");

public:
  typedef VectorImp VectorType;
  typedef typename VectorType::ScalarType ScalarType;

  template <class M, class EntityType>
  ConstLocalDoFVector(const MapperInterface<M>& mapper, const EntityType& entity, const VectorType& vector)
    : vector_(vector)
    , indices_(mapper.numDofs(entity))
  {
    mapper.globalIndices(entity, indices_);
  }

  ~ConstLocalDoFVector()
  {
  }

  size_t size() const
  {
    return indices_.size();
  }

  ScalarType get(const size_t ii) const
  {
    assert(ii < indices_.size());
    return vector_.get_entry(indices_[ii]);
  }

private:
  const VectorType& vector_;

protected:
  Dune::DynamicVector<size_t> indices_;

private:
  template <class V>
  friend std::ostream& operator<<(std::ostream& /*out*/, const ConstLocalDoFVector<V>& /*vector*/);
}; // class ConstLocalDoFVector

template <class V>
std::ostream& operator<<(std::ostream& out, const ConstLocalDoFVector<V>& vector)
{
  out << "[";
  const size_t sz = vector.size();
  if (sz > 0) {
    out << vector.get(0);
    for (size_t ii = 1; ii < sz; ++ii)
      out << ", " << vector.get(ii);
  } else
    out << " ";
  out << "]";
  return out;
} // ... operator<<(...)

template <class VectorImp>
class LocalDoFVector : public ConstLocalDoFVector<VectorImp>
{
  typedef ConstLocalDoFVector<VectorImp> BaseType;

public:
  typedef typename BaseType::VectorType VectorType;
  typedef typename BaseType::ScalarType ScalarType;

  template <class M, class EntityType>
  LocalDoFVector(const MapperInterface<M>& mapper, const EntityType& entity, VectorType& vector)
    : BaseType(mapper, entity, vector)
    , vector_(vector)
  {
  }

  ~LocalDoFVector()
  {
  }

  void set(const size_t ii, const ScalarType& val)
  {
    assert(ii < indices_.size());
    vector_.set_entry(indices_[ii], val);
  }

  void add(const size_t ii, const ScalarType& val)
  {
    assert(ii < indices_.size());
    vector_.add_to_entry(indices_[ii], val);
  }

  template <class OtherVectorImp>
  void add(const OtherVectorImp& vector)
  {
    assert(vector.size() == indices_.size());
    for (size_t ii = 0; ii < indices_.size(); ++ii)
      add(ii, vector[ii]);
  }

private:
  using BaseType::indices_;
  VectorType& vector_;
}; // class LocalDoFVector

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_DOF_VECTOR_HH
<commit_msg>[local.dof-vector] complete rewrite<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2016 - 2017)
//   Rene Milk       (2016 - 2017)

#ifndef DUNE_GDT_LOCAL_DOF_VECTOR_HH
#define DUNE_GDT_LOCAL_DOF_VECTOR_HH

#include <dune/xt/common/vector.hh>
#include <dune/xt/la/container/vector-interface.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/spaces/mapper/interfaces.hh>

namespace Dune {
namespace GDT {
namespace internal {

// forward, required for the default in the declaration of ConstLocalDofVector
template <class Vector, class GridView>
class ConstLocalDofVectorTraits;

} // namespace internal

// forwards, required for the traits
template <class Vector, class GridView, class Traits = internal::ConstLocalDofVectorTraits<Vector, GridView>>
class ConstLocalDofVector;

template <class Vector, class GridView>
class LocalDofVector;

namespace internal {

template <class Vector, class GridView>
class ConstLocalDofVectorTraits
{
  static_assert(XT::LA::is_vector<Vector>::value, "");

public:
  using derived_type = ConstLocalDofVector<Vector, GridView>;
  using ScalarType = typename Vector::ScalarType;
};

template <class Vector, class GridView>
class LocalDofVectorTraits
{
  static_assert(XT::LA::is_vector<Vector>::value, "");

public:
  using derived_type = LocalDofVector<Vector, GridView>;
  using ScalarType = typename Vector::ScalarType;
};

} // namespace internal

/**
 * \note Since all implementations of XT::LA::VectorInterface are assumed to be thread safe, no special care needs to be
 *       taken here.
 */
template <class Vector, class GridView, class Traits>
class ConstLocalDofVector : public XT::LA::VectorInterface<Traits>
{

  using ThisType = ConstLocalDofVector<Vector, GridView, Traits>;
  using BaseType = XT::LA::VectorInterface<Traits>;

public:
  using typename BaseType::ScalarType;
  using VectorType = Vector;
  using MapperType = MapperInterface<GridView>;
  using ElementType = typename MapperType::ElementType;

  ConstLocalDofVector(const MapperType& mapper, const VectorType& global_vector)
    : mapper_(mapper)
    , global_vector_(global_vector)
    , global_DoF_indices_(mapper_.max_local_size())
    , size_(0)
    , element_(nullptr)
  {
  }

  // Cannot be defaulted due to element_.
  ConstLocalDofVector(const MapperType& mapper, const VectorType& global_vector, const ElementType& element)
    : mapper_(mapper)
    , global_vector_(global_vector)
    , global_DoF_indices_(mapper_.max_local_size())
    , size_(0)
    , element_(nullptr)
  {
    this->bind(element);
  }

  // Cannot be defaulted due to element_.
  ConstLocalDofVector(const ThisType& other)
    : mapper_(other.mapper_)
    , global_vector_(other.global_vector_)
    , global_DoF_indices_(other.global_DoF_indices_)
    , size_(other.size_)
    , element_(other.element_ ? std::make_unique<ElementType>(*other.element_) : nullptr)
  {
  }

  ConstLocalDofVector(ThisType&& source)
    : mapper_(source.mapper_)
    , global_vector_(source.global_vector_)
    , global_DoF_indices_(std::move(source.global_DoF_indices_))
    , size_(std::move(source.size_))
    , element_(std::move(source.element_))
  {
  }

  ThisType& bind(const ElementType& new_element)
  {
    if (!element_ || new_element != *element_) {
      element_ = std::make_unique<ElementType>(new_element);
      mapper_.global_indices(*element_, global_DoF_indices_);
      size_ = mapper_.local_size(*element_);
      assert(global_DoF_indices_.size() >= size_ && "This must not happen, the mapper is broken!");
    }
    return *this;
  } // ... bind(...)

  size_t size() const
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    return size_;
  }

  void add_to_entry(const size_t /*ii*/, const ScalarType& /*value*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
  }

  void set_entry(const size_t /*ii*/, const ScalarType& /*value*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
  }

  ScalarType get_entry(const size_t ii) const
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    return global_vector_.get_entry(global_DoF_indices_[ii]);
  }

protected:
  ScalarType& get_unchecked_ref(const size_t /*ii*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
    return dummy_scalar_to_silence_the_warning_;
  }

  const ScalarType& get_unchecked_ref(const size_t ii) const
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    // This is not optimal, but global_vector_.get_unchecked_ref is protected.
    return global_vector_[global_DoF_indices_[ii]];
  }

public:
  ScalarType& operator[](const size_t /*ii*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
    return dummy_scalar_to_silence_the_warning_;
  }

  const ScalarType& operator[](const size_t ii) const
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

protected:
  friend BaseType; // To allow access to get_unchecked_ref().

  const MapperType& mapper_;

private:
  const VectorType& global_vector_;

protected:
  DynamicVector<size_t> global_DoF_indices_;
  size_t size_;
  std::unique_ptr<ElementType> element_;

private:
  ScalarType dummy_scalar_to_silence_the_warning_;
}; // class ConstLocalDofVector

template <class Vector, class GridView>
class LocalDofVector : public ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>>
{

  using ThisType = LocalDofVector<Vector, GridView>;
  using BaseType = ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>>;

public:
  using typename BaseType::ScalarType;
  using VectorType = Vector;
  using MapperType = MapperInterface<GridView>;
  using ElementType = typename MapperType::ElementType;

  LocalDofVector(const MapperType& mapper, VectorType& global_vector)
    : BaseType(mapper, global_vector)
    , global_vector_(global_vector)
  {
  }

  LocalDofVector(const MapperType& mapper, VectorType& global_vector, const ElementType& element)
    : BaseType(mapper, global_vector, element)
    , global_vector_(global_vector)
  {
  }

  LocalDofVector(const ThisType&) = default;
  LocalDofVector(ThisType&&) = default;

  void add_to_entry(const size_t ii, const ScalarType& value)
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    global_vector_.add_to_entry(global_DoF_indices_[ii], value);
  }

  void set_entry(const size_t ii, const ScalarType& value)
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    global_vector_.set_entry(global_DoF_indices_[ii], value);
  }

  ScalarType get_entry(const size_t ii) const
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    return global_vector_.get_entry(global_DoF_indices_[ii]);
  }

protected:
  ScalarType& get_unchecked_ref(const size_t ii)
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

  const ScalarType& get_unchecked_ref(const size_t ii) const
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

public:
  ScalarType& operator[](const size_t ii)
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

  const ScalarType& operator[](const size_t ii) const
  {
    DUNE_THROW_IF(!element_, Exceptions::not_bound_to_an_element_yet, "you need to call bind() first!");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

private:
  // To allow access to get_unchecked_ref().
  friend XT::LA::VectorInterface<internal::LocalDofVectorTraits<Vector, GridView>>;

  using BaseType::mapper_;
  VectorType& global_vector_;
  using BaseType::global_DoF_indices_;
  using BaseType::size_;
  using BaseType::element_;
}; // class LocalDofVector

} // namespace GDT
namespace XT {
namespace Common {

template <class Vector, class GridView, class Traits>
struct VectorAbstraction<GDT::ConstLocalDofVector<Vector, GridView, Traits>>
    : public LA::internal::VectorAbstractionBase<GDT::ConstLocalDofVector<Vector, GridView, Traits>>
{
};

template <class Vector, class GridView>
struct VectorAbstraction<GDT::LocalDofVector<Vector, GridView>>
    : public LA::internal::VectorAbstractionBase<GDT::LocalDofVector<Vector, GridView>>
{
};

} // namespace Common
} // namespace XT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_DOF_VECTOR_HH
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_FVECTOR_HH
#define DUNE_STUFF_COMMON_FVECTOR_HH

#include <vector>
#include <initializer_list>

#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/fvector.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/debug.hh>

namespace Dune {
namespace Stuff {
namespace Common {

template< class K, int SIZE >
class FieldVector
  : public Dune::FieldVector< K, SIZE >
{
  typedef Dune::FieldVector< K, SIZE > BaseType;
  typedef FieldVector< K, SIZE >       ThisType;

public:
  FieldVector(const K kk = K(0))
    : BaseType(kk)
  {}

  FieldVector(const size_t UNUSED_UNLESS_DEBUG(sz), const K kk)
    : BaseType(kk)
  {
#ifndef NDEBUG
    if (sz != SIZE)
      DUNE_THROW(Exceptions::wrong_input_given,
                 "You are trying to construct a FieldVector< ..., " << SIZE << " > (of " << "static size) with " << sz
                 << " elements!");
#endif // NDEBUG
  } // ... FieldVector(...)

  FieldVector(const BaseType& other)
    : BaseType(other)
  {}

  FieldVector(const std::vector< K >& vec)
    : BaseType(K(0))
  {
#ifndef NDEBUG
    if (vec.size() != SIZE)
      DUNE_THROW(Exceptions::wrong_input_given,
                 "You are trying to construct a FieldVector< ..., " << SIZE << " > (of "
                 << "static size) from a vector of size " << vec.size() << "!");
#endif // NDEBUG
    for (size_t ii = 0; ii < SIZE; ++ii)
      this->operator[](ii) = vec[ii];
  } // FieldVector(...)

  FieldVector(std::initializer_list< K > list)
    : BaseType(K(0))
  {
#ifndef NDEBUG
    if (list.size() != SIZE)
      DUNE_THROW(Exceptions::wrong_input_given,
                 "You are trying to construct a FieldVector< ..., " << SIZE << " > (of "
                 << "static size) from a list of size " << list.size() << "!");
#endif // NDEBUG
    size_t ii = 0;
    for (auto element : list) {
      this->operator[](ii) = element;
      ++ii;
    }
  } // FieldVector(...)

  ThisType& operator=(const BaseType& other)
  {
    BaseType::operator=(other);
    return *this;
  }

  using BaseType::operator*;

  ThisType operator*(const K& scalar) const
  {
    ThisType ret(*this);
    ret *= scalar;
    return ret;
  }
}; // class FieldVector

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_FVECTOR_HH
<commit_msg>[common.fvector] minor change<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_FVECTOR_HH
#define DUNE_STUFF_COMMON_FVECTOR_HH

#include <vector>
#include <initializer_list>

#include <dune/stuff/common/disable_warnings.hh>
# include <dune/common/fvector.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/debug.hh>

namespace Dune {
namespace Stuff {
namespace Common {

template< class K, int SIZE >
class FieldVector
  : public Dune::FieldVector< K, SIZE >
{
  typedef Dune::FieldVector< K, SIZE > BaseType;
  typedef FieldVector< K, SIZE >       ThisType;

public:
  FieldVector(const K kk = K(0))
    : BaseType(kk)
  {}

  FieldVector(const size_t UNUSED_UNLESS_DEBUG(sz), const K kk)
    : BaseType(kk)
  {
#ifndef NDEBUG
    if (sz != SIZE)
      DUNE_THROW(Exceptions::wrong_input_given,
                 "You are trying to construct a FieldVector< ..., " << SIZE << " > (of " << "static size) with " << sz
                 << " elements!");
#endif // NDEBUG
  } // ... FieldVector(...)

  FieldVector(const BaseType& other)
    : BaseType(other)
  {}

  FieldVector(const std::vector< K >& vec)
    : BaseType(K(0))
  {
#ifndef NDEBUG
    if (vec.size() != SIZE)
      DUNE_THROW(Exceptions::wrong_input_given,
                 "You are trying to construct a FieldVector< ..., " << SIZE << " > (of "
                 << "static size) from a vector of size " << vec.size() << "!");
#endif // NDEBUG
    for (size_t ii = 0; ii < SIZE; ++ii)
      this->operator[](ii) = vec[ii];
  } // FieldVector(...)

  FieldVector(std::initializer_list< K > list)
    : BaseType(K(0))
  {
#ifndef NDEBUG
    if (list.size() != SIZE)
      DUNE_THROW(Exceptions::wrong_input_given,
                 "You are trying to construct a FieldVector< ..., " << SIZE << " > (of "
                 << "static size) from a list of size " << list.size() << "!");
#endif // NDEBUG
    size_t ii = 0;
    for (auto element : list)
      this->operator[](ii++) = element;
  } // FieldVector(...)

  ThisType& operator=(const BaseType& other)
  {
    BaseType::operator=(other);
    return *this;
  }

  using BaseType::operator*;

  ThisType operator*(const K& scalar) const
  {
    ThisType ret(*this);
    ret *= scalar;
    return ret;
  }
}; // class FieldVector

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_FVECTOR_HH
<|endoftext|>


<commit_before>/**
   *  \file logging.hh
   *  \brief  logging
   **/
#ifndef LOGGING_HH_INCLUDED
#define LOGGING_HH_INCLUDED

#include <fstream>
#include <ostream>
#include <sstream>
#include <ctime>
#include <iomanip>
#include <map>
#include <assert.h>
#include "misc.hh"
#include "filesystem.hh"
#include "logstreams.hh"
#include "string.hh"

#include <boost/range/adaptors.hpp>

namespace Dune {
namespace Stuff {
namespace Common {
class Logging;
Logging& Logger();

/** \brief handles all logging
  **/
class Logging
{
private:
  Logging()
    : matlabLogStreamPtr(0) {
    streamIDs_.push_back(LOG_ERR);
    streamIDs_.push_back(LOG_DEBUG);
    streamIDs_.push_back(LOG_INFO);
  }

public:
  ~Logging() {
    //destroy in reverse creation order, 2012 style
    for ( auto id :  boost::adaptors::reverse(streamIDs_))
    {
      //logstream dtor is mandated to flush itself
      delete streammap_[id];
      streammap_[id] = 0;
    }

    if ( (logflags_ & LOG_FILE) != 0 )
    {
      logfile_ << '\n' << Dune::Stuff::Common::String::fromTime() << ": LOG END" << std::endl;
      logfileWoTime_ << std::endl;
      logfile_.close();
      logfileWoTime_.close();
    }

    // delete the MatlabLogStream
    matlabLogStreamPtr->flush();
    matlabLogFile_.close();
    delete matlabLogStreamPtr;
    matlabLogStreamPtr = 0;
  }

  /** \brief setup loglevel, logfilename
     *  \param logflags any OR'd combination of flags
     *  \param logfile filename for log, can contain paths, but creation will fail if dir is non-existant
     **/
  void create( unsigned int logflags = LOG_FILE | LOG_CONSOLE | LOG_ERR,
               std::string logfile = "dune_stuff_log",
               std::string datadir = "data",
               std::string logdir = std::string("") ) {
    logflags_ = logflags;

    // if we get a logdir from parameters append path seperator, otherwise leave empty
    // enables us to use logdir unconditionally further down
    if ( !datadir.empty() )
      datadir += "/";
    if ( !logdir.empty() )
      logdir += "/";
    logdir = datadir + logdir;

    filename_ = logdir + logfile + "_time.log";
    Stuff::Common::Filesystem::testCreateDirectory(logdir);

    filenameWoTime_ = logdir + logfile + ".log";
    if ( (logflags_ & LOG_FILE) != 0 )
    {
      logfile_.open( filename_.c_str() );
      assert( logfile_.is_open() );
      logfileWoTime_.open( filenameWoTime_.c_str() );
      assert( logfileWoTime_.is_open() );
    }
    IdVecCIter it = streamIDs_.begin();
    for ( ; it != streamIDs_.end(); ++it)
    {
      flagmap_[*it] = logflags;
      streammap_[*it] = new LogStream(*it, flagmap_[*it], logfile_, logfileWoTime_);
    }
    // create the MatlabLogStream
    std::string matlabLogFileName = logdir + logfile + "_matlab.m";
    Stuff::Common::Filesystem::testCreateDirectory(matlabLogFileName);           // could assert this if i figure out
                                                                                // why errno is != EEXIST
    matlabLogFile_.open( matlabLogFileName.c_str() );
    assert( matlabLogFile_.is_open() );
    matlabLogStreamPtr = new MatlabLogStream(LOG_FILE, logflags_, matlabLogFile_);
  } // Create

  // ! \attention This will probably not do wht we want it to!
  void setPrefix(std::string prefix) {
    // / begin dtor
    IdVecCIter it = streamIDs_.end();

    for ( ; it != streamIDs_.begin(); --it)
    {
      delete streammap_[*it];
      streammap_[*it] = 0;
    }

    if ( (logflags_ & LOG_FILE) != 0 )
    {
      logfile_ << '\n' << Dune::Stuff::Common::String::fromTime() << ": LOG END" << std::endl;
      logfileWoTime_ << std::endl;
      logfile_.close();
      logfileWoTime_.close();
    }

    // delete the MatlabLogStream
    matlabLogStreamPtr->flush();
    matlabLogFile_.close();
    delete matlabLogStreamPtr;
    matlabLogStreamPtr = 0;
    // / end dtor

    create(logflags_, prefix);
  } // SetPrefix

  void setStreamFlags(LogFlags streamID, int flags) {
    assert( flagmap_.find(streamID) != flagmap_.end() );
    // this might result in logging to diff targtes, so we flush the current targets
    flush();
    flagmap_[streamID] = flags;
  }

  int getStreamFlags(LogFlags streamID) const {
    const auto it = flagmap_.find(streamID);
    if (it == flagmap_.end())
      DUNE_THROW(InvalidStateException, "cannot get flags for unkown Stream id");
    return it->second;
  }

  /** \name forwarded Log functions
     * \{
     */
  template< typename Pointer, class Class >
  void log(void (Class::* pf)(std::ostream &) const, Class& c, LogFlags streamID) {
    getStream(streamID).log(pf, c);
  } // Log

  template< class Class, typename Pointer >
  void log(Pointer pf, Class& c, LogFlags streamID) {
    getStream(streamID).log(pf, c);
  } // Log

  template< class T >
  void log(T c, LogFlags streamID) {
    getStream(streamID) << c;
  } // Log

  /** \}
     */

  LogStream& getStream(LogFlags stream) {
    const auto it = streammap_.find(stream);
    if (it == streammap_.end())
      DUNE_THROW(InvalidStateException, "cannot get unkown Stream");
    return *(it->second);
  }

  LogStream& err() { return getStream(LOG_ERR); }
  LogStream& info() { return getStream(LOG_INFO); }
  LogStream& dbg() DUNE_DEPRECATED_MSG("use debug() instead") { return getStream(LOG_DEBUG); }
  LogStream& debug() { return getStream(LOG_DEBUG); }
  MatlabLogStream& matlab() { assert(matlabLogStreamPtr); return *matlabLogStreamPtr; }

  void flush() {
    for (auto pair : streammap_)
      pair.second->flush();
  } // Flush

  int addStream(LogFlags flags) {
//    assert( streamIDs_.find(flags) == streamIDs_.end() );
    static int streamID_int = 16;
    streamID_int <<= 2;
    LogFlags streamID = (LogFlags) streamID_int;
    streamIDs_.push_back(streamID);
    flagmap_[streamID] = flags | streamID;
    streammap_[streamID] = new LogStream(streamID, flagmap_[streamID], logfile_, logfileWoTime_);
    return streamID_int;
  } // AddStream

  void resume(LogStream::PriorityType prio = LogStream::default_suspend_priority) {
    for (auto pair : streammap_)
      pair.second->resume(prio);
  } // Resume

  void suspend(LogStream::PriorityType prio = LogStream::default_suspend_priority) {
    for (auto pair : streammap_)
      pair.second->suspend(prio);
  } // Suspend

  struct SuspendLocal
  {
    LogStream::PriorityType prio_;
    SuspendLocal(LogStream::PriorityType prio = LogStream::default_suspend_priority)
      : prio_(prio) {
      Logger().suspend(prio_);
    }

    ~SuspendLocal() {
      Logger().resume(prio_);
    }
  };

  struct ResumeLocal
  {
    LogStream::PriorityType prio_;
    ResumeLocal(LogStream::PriorityType prio = LogStream::default_suspend_priority)
      : prio_(prio) {
      Logger().resume(prio_);
    }

    ~ResumeLocal() {
      Logger().suspend(prio_);
    }
  };

private:
  std::string filename_;
  std::string filenameWoTime_;
  std::ofstream logfile_;
  std::ofstream logfileWoTime_;
  std::ofstream matlabLogFile_;
  typedef std::map< LogFlags, int > FlagMap;
  FlagMap flagmap_;
  typedef std::map< LogFlags, LogStream* > StreamMap;
  StreamMap streammap_;
  typedef std::vector< LogFlags >                 IdVec;
  typedef std::vector< LogFlags >::const_iterator IdVecCIter;
  IdVec streamIDs_;
  int logflags_;
  MatlabLogStream* matlabLogStreamPtr;

  friend Logging& Logger();
  // satisfy stricter warnings wrt copying
  Logging(const Logging&);
  Logging& operator=(const Logging&);
};

// !global Logging instance
Logging& Logger() {
  static Logging log;
  return log;
}
} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // ifndef LOGGING_HH_INCLUDED

/** Copyright (c) 2012, Rene Milk
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, this
   *    list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * The views and conclusions contained in the software and documentation are those
   * of the authors and should not be interpreted as representing official policies,
   * either expressed or implied, of the FreeBSD Project.
   **/
<commit_msg>[stuff.common.logging] use BOOST_FOREACH to comply with gcc-4.4<commit_after>/**
   *  \file logging.hh
   *  \brief  logging
   **/
#ifndef LOGGING_HH_INCLUDED
#define LOGGING_HH_INCLUDED

#include <fstream>
#include <ostream>
#include <sstream>
#include <ctime>
#include <iomanip>
#include <map>
#include <assert.h>
#include "misc.hh"
#include "filesystem.hh"
#include "logstreams.hh"
#include "string.hh"

#include <boost/range/adaptors.hpp>
#include <boost/foreach.hpp>

namespace Dune {
namespace Stuff {
namespace Common {
class Logging;
Logging& Logger();

/** \brief handles all logging
  **/
class Logging
{
private:
  Logging()
    : matlabLogStreamPtr(0) {
    streamIDs_.push_back(LOG_ERR);
    streamIDs_.push_back(LOG_DEBUG);
    streamIDs_.push_back(LOG_INFO);
  }

public:
  ~Logging() {
    //destroy in reverse creation order, 2012 style
    BOOST_REVERSE_FOREACH(auto id, streamIDs_)
    {
      //logstream dtor is mandated to flush itself
      delete streammap_[id];
      streammap_[id] = 0;
    }

    if ( (logflags_ & LOG_FILE) != 0 )
    {
      logfile_ << '\n' << Dune::Stuff::Common::String::fromTime() << ": LOG END" << std::endl;
      logfileWoTime_ << std::endl;
      logfile_.close();
      logfileWoTime_.close();
    }

    // delete the MatlabLogStream
    matlabLogStreamPtr->flush();
    matlabLogFile_.close();
    delete matlabLogStreamPtr;
    matlabLogStreamPtr = 0;
  }

  /** \brief setup loglevel, logfilename
     *  \param logflags any OR'd combination of flags
     *  \param logfile filename for log, can contain paths, but creation will fail if dir is non-existant
     **/
  void create( unsigned int logflags = LOG_FILE | LOG_CONSOLE | LOG_ERR,
               std::string logfile = "dune_stuff_log",
               std::string datadir = "data",
               std::string logdir = std::string("") ) {
    logflags_ = logflags;

    // if we get a logdir from parameters append path seperator, otherwise leave empty
    // enables us to use logdir unconditionally further down
    if ( !datadir.empty() )
      datadir += "/";
    if ( !logdir.empty() )
      logdir += "/";
    logdir = datadir + logdir;

    filename_ = logdir + logfile + "_time.log";
    Stuff::Common::Filesystem::testCreateDirectory(logdir);

    filenameWoTime_ = logdir + logfile + ".log";
    if ( (logflags_ & LOG_FILE) != 0 )
    {
      logfile_.open( filename_.c_str() );
      assert( logfile_.is_open() );
      logfileWoTime_.open( filenameWoTime_.c_str() );
      assert( logfileWoTime_.is_open() );
    }
    IdVecCIter it = streamIDs_.begin();
    for ( ; it != streamIDs_.end(); ++it)
    {
      flagmap_[*it] = logflags;
      streammap_[*it] = new LogStream(*it, flagmap_[*it], logfile_, logfileWoTime_);
    }
    // create the MatlabLogStream
    std::string matlabLogFileName = logdir + logfile + "_matlab.m";
    Stuff::Common::Filesystem::testCreateDirectory(matlabLogFileName);           // could assert this if i figure out
                                                                                // why errno is != EEXIST
    matlabLogFile_.open( matlabLogFileName.c_str() );
    assert( matlabLogFile_.is_open() );
    matlabLogStreamPtr = new MatlabLogStream(LOG_FILE, logflags_, matlabLogFile_);
  } // Create

  // ! \attention This will probably not do wht we want it to!
  void setPrefix(std::string prefix) {
    // / begin dtor
    IdVecCIter it = streamIDs_.end();

    for ( ; it != streamIDs_.begin(); --it)
    {
      delete streammap_[*it];
      streammap_[*it] = 0;
    }

    if ( (logflags_ & LOG_FILE) != 0 )
    {
      logfile_ << '\n' << Dune::Stuff::Common::String::fromTime() << ": LOG END" << std::endl;
      logfileWoTime_ << std::endl;
      logfile_.close();
      logfileWoTime_.close();
    }

    // delete the MatlabLogStream
    matlabLogStreamPtr->flush();
    matlabLogFile_.close();
    delete matlabLogStreamPtr;
    matlabLogStreamPtr = 0;
    // / end dtor

    create(logflags_, prefix);
  } // SetPrefix

  void setStreamFlags(LogFlags streamID, int flags) {
    assert( flagmap_.find(streamID) != flagmap_.end() );
    // this might result in logging to diff targtes, so we flush the current targets
    flush();
    flagmap_[streamID] = flags;
  }

  int getStreamFlags(LogFlags streamID) const {
    const auto it = flagmap_.find(streamID);
    if (it == flagmap_.end())
      DUNE_THROW(InvalidStateException, "cannot get flags for unkown Stream id");
    return it->second;
  }

  /** \name forwarded Log functions
     * \{
     */
  template< typename Pointer, class Class >
  void log(void (Class::* pf)(std::ostream &) const, Class& c, LogFlags streamID) {
    getStream(streamID).log(pf, c);
  } // Log

  template< class Class, typename Pointer >
  void log(Pointer pf, Class& c, LogFlags streamID) {
    getStream(streamID).log(pf, c);
  } // Log

  template< class T >
  void log(T c, LogFlags streamID) {
    getStream(streamID) << c;
  } // Log

  /** \}
     */

  LogStream& getStream(LogFlags stream) {
    const auto it = streammap_.find(stream);
    if (it == streammap_.end())
      DUNE_THROW(InvalidStateException, "cannot get unkown Stream");
    return *(it->second);
  }

  LogStream& err() { return getStream(LOG_ERR); }
  LogStream& info() { return getStream(LOG_INFO); }
  LogStream& dbg() DUNE_DEPRECATED_MSG("use debug() instead") { return getStream(LOG_DEBUG); }
  LogStream& debug() { return getStream(LOG_DEBUG); }
  MatlabLogStream& matlab() { assert(matlabLogStreamPtr); return *matlabLogStreamPtr; }

  void flush() {
    BOOST_FOREACH(auto pair, streammap_)
    {
      pair.second->flush();
    }
  } // Flush

  int addStream(LogFlags flags) {
//    assert( streamIDs_.find(flags) == streamIDs_.end() );
    static int streamID_int = 16;
    streamID_int <<= 2;
    LogFlags streamID = (LogFlags) streamID_int;
    streamIDs_.push_back(streamID);
    flagmap_[streamID] = flags | streamID;
    streammap_[streamID] = new LogStream(streamID, flagmap_[streamID], logfile_, logfileWoTime_);
    return streamID_int;
  } // AddStream

  void resume(LogStream::PriorityType prio = LogStream::default_suspend_priority) {
    BOOST_FOREACH(auto pair, streammap_)
    {
      pair.second->resume(prio);
    }
  } // Resume

  void suspend(LogStream::PriorityType prio = LogStream::default_suspend_priority) {
    BOOST_FOREACH(auto pair, streammap_)
    {
      pair.second->suspend(prio);
    }
  } // Suspend

  struct SuspendLocal
  {
    LogStream::PriorityType prio_;
    SuspendLocal(LogStream::PriorityType prio = LogStream::default_suspend_priority)
      : prio_(prio) {
      Logger().suspend(prio_);
    }

    ~SuspendLocal() {
      Logger().resume(prio_);
    }
  };

  struct ResumeLocal
  {
    LogStream::PriorityType prio_;
    ResumeLocal(LogStream::PriorityType prio = LogStream::default_suspend_priority)
      : prio_(prio) {
      Logger().resume(prio_);
    }

    ~ResumeLocal() {
      Logger().suspend(prio_);
    }
  };

private:
  std::string filename_;
  std::string filenameWoTime_;
  std::ofstream logfile_;
  std::ofstream logfileWoTime_;
  std::ofstream matlabLogFile_;
  typedef std::map< LogFlags, int > FlagMap;
  FlagMap flagmap_;
  typedef std::map< LogFlags, LogStream* > StreamMap;
  StreamMap streammap_;
  typedef std::vector< LogFlags >                 IdVec;
  typedef std::vector< LogFlags >::const_iterator IdVecCIter;
  IdVec streamIDs_;
  int logflags_;
  MatlabLogStream* matlabLogStreamPtr;

  friend Logging& Logger();
  // satisfy stricter warnings wrt copying
  Logging(const Logging&);
  Logging& operator=(const Logging&);
};

// !global Logging instance
Logging& Logger() {
  static Logging log;
  return log;
}
} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // ifndef LOGGING_HH_INCLUDED

/** Copyright (c) 2012, Rene Milk
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, this
   *    list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * The views and conclusions contained in the software and documentation are those
   * of the authors and should not be interpreted as representing official policies,
   * either expressed or implied, of the FreeBSD Project.
   **/
<|endoftext|>


<commit_before>#include <json/json.h>
#include <json/value.h>

#include <libdvid/DVIDNode.h>

#include <iostream>
#include <string>
#include <fstream>

#include <vector>
#include <tr1/unordered_map>
#include <tr1/unordered_set>

using std::cout; using std::endl;
using std::ifstream;

using std::string;
using std::tr1::unordered_map;
using std::tr1::unordered_set;
using std::vector;

const char * USAGE = "<prog> <dvid-server> <uuid> <graph-name> <synapse-file> <label name>";
const char * HELP = "Program takes a synapse file (in global DVID coordinates) and saves the counts and partners in the given graph";
static const char * SYNAPSE_KEY = "synapse";

int main(int argc, char** argv)
{
    if (argc != 6) {
        cout << USAGE << endl;
        cout << HELP << endl;
        exit(1);
    }

    // create DVID node accessor
    libdvid::DVIDServer server(argv[1]);
    libdvid::DVIDNode dvid_node(server, argv[2]);

    string graph_name = string(argv[3]);

    unordered_map<unsigned long long, unsigned long long> counts;
    unordered_map<unsigned long long, unordered_set<unsigned long long> > partners;

    // size and channel params for standard label rest call
    libdvid::tuple sizes; sizes.push_back(1);
    sizes.push_back(2); sizes.push_back(3);

    libdvid::tuple channels; channels.push_back(0);
    channels.push_back(1); channels.push_back(2);

    // read synapse file
    Json::Reader json_reader;
    Json::Value json_reader_vals;
    ifstream fin(argv[4]);
    if (!fin) {
        cout << "Error: input file: " << argv[4] << " cannot be opened" << endl;
        exit(1);
    }
    if (!json_reader.parse(fin, json_reader_vals)) {
        cout << "Error: Json incorrectly formatted" << endl;
        exit(1);
    }
    fin.close();

    // iterate all synapses
    Json::Value synapses = json_reader_vals["data"];
    for (int i = 0; i < synapses.size(); ++i) {
        vector<unsigned int> constraint_list;

        Json::Value location = synapses[i]["T-bar"]["location"];
        if (!location.empty()) {
            int xloc = location[(unsigned int)(0)].asUInt();
            int yloc = location[(unsigned int)(1)].asUInt();
            int zloc = location[(unsigned int)(2)].asUInt();

            // determine label corresponding to point
            libdvid::tuple start; start.push_back(xloc);
            start.push_back(yloc); start.push_back(zloc);

            // retrieve volume
            libdvid::DVIDLabelPtr labels;
            dvid_node.get_volume_roi(argv[5], start, sizes, channels, labels);
            unsigned long long* ptr = (unsigned long long int*) labels->get_raw();
            unsigned long long label = *ptr;

            if (label) {
                constraint_list.push_back(label);
                counts[label]++;
            }
        }
        Json::Value psds = synapses[i]["partners"];
        for (int i = 0; i < psds.size(); ++i) {
            Json::Value location = psds[i]["location"];
            if (!location.empty()) {
                int xloc = location[(unsigned int)(0)].asUInt();
                int yloc = location[(unsigned int)(1)].asUInt();
                int zloc = location[(unsigned int)(2)].asUInt();

                // determine label corresponding to point
                libdvid::tuple start; start.push_back(xloc);
                start.push_back(yloc); start.push_back(zloc);

                // retrieve volume
                libdvid::DVIDLabelPtr labels;
                dvid_node.get_volume_roi(argv[5], start, sizes, channels, labels);
                unsigned long long* ptr = (unsigned long long int*) labels->get_raw();
                unsigned long long label = *ptr;

                if (label) {
                    constraint_list.push_back(label);
                    counts[label]++;
                }
            }
        }

        // load constraints for Tbar to PSD and PSD to PSD
        for (int it1 = 0; it1 < constraint_list.size(); ++it1) {
            for (int it2 = (it1+1); it2 < constraint_list.size(); ++it2) {
                if (constraint_list[it1] != constraint_list[it2]) {
                    partners[(constraint_list[it1])].insert((constraint_list[it2]));
                    partners[(constraint_list[it2])].insert((constraint_list[it1]));
                }
            }
        }
    }

    // load vertex list and data
    vector<libdvid::Vertex> vertices;
    vector<libdvid::BinaryDataPtr> properties;
    libdvid::VertexTransactions transaction_ids;

    // load property data for post
    for (unordered_map<unsigned long long, unsigned long long>::iterator iter =
            counts.begin(); iter != counts.end(); ++iter) {
        vertices.push_back(libdvid::Vertex(iter->first, 0));

        // set count and constraints
        unsigned long long num_partners = partners[iter->first].size();
        int total_size = num_partners + 2;
        assert(sizeof(unsigned long long) == 8);

        unsigned long long* data = new unsigned long long [total_size];

        int spot = 0;
        data[spot] = iter->second;
        ++spot;
        data[spot] = num_partners;
        ++spot;
        for (unordered_set<unsigned long long>::iterator iter2 =
            partners[iter->first].begin(); iter2 != partners[iter->first].end(); ++iter2) {
            data[spot] = *iter2;
            ++spot;
        }

        properties.push_back(libdvid::BinaryData::create_binary_data((char*) data,
                    total_size*8));

        delete []data;
    }

    // nominally use transaction protection to load data; this should be run by itself
    vector<libdvid::BinaryDataPtr> properties_dummy;
    // retrieve vertex transactions
    dvid_node.get_properties(graph_name, vertices, SYNAPSE_KEY,
            properties_dummy, transaction_ids);

    // set vertex transactions
    vector<libdvid::Vertex> leftover_vertices;
    dvid_node.set_properties(graph_name, vertices, SYNAPSE_KEY, properties,
            transaction_ids, leftover_vertices);

    assert(leftover_vertices.size() == 0);

    return 0;
}

<commit_msg>fixes small inefficiency in calling larger than needed block<commit_after>#include <json/json.h>
#include <json/value.h>

#include <libdvid/DVIDNode.h>

#include <iostream>
#include <string>
#include <fstream>

#include <vector>
#include <tr1/unordered_map>
#include <tr1/unordered_set>

using std::cout; using std::endl;
using std::ifstream;

using std::string;
using std::tr1::unordered_map;
using std::tr1::unordered_set;
using std::vector;

const char * USAGE = "<prog> <dvid-server> <uuid> <graph-name> <synapse-file> <label name>";
const char * HELP = "Program takes a synapse file (in global DVID coordinates) and saves the counts and partners in the given graph";
static const char * SYNAPSE_KEY = "synapse";

int main(int argc, char** argv)
{
    if (argc != 6) {
        cout << USAGE << endl;
        cout << HELP << endl;
        exit(1);
    }

    // create DVID node accessor
    libdvid::DVIDServer server(argv[1]);
    libdvid::DVIDNode dvid_node(server, argv[2]);

    string graph_name = string(argv[3]);

    unordered_map<unsigned long long, unsigned long long> counts;
    unordered_map<unsigned long long, unordered_set<unsigned long long> > partners;

    // size and channel params for standard label rest call
    libdvid::tuple sizes; sizes.push_back(1);
    sizes.push_back(1); sizes.push_back(1);

    libdvid::tuple channels; channels.push_back(0);
    channels.push_back(1); channels.push_back(2);

    // read synapse file
    Json::Reader json_reader;
    Json::Value json_reader_vals;
    ifstream fin(argv[4]);
    if (!fin) {
        cout << "Error: input file: " << argv[4] << " cannot be opened" << endl;
        exit(1);
    }
    if (!json_reader.parse(fin, json_reader_vals)) {
        cout << "Error: Json incorrectly formatted" << endl;
        exit(1);
    }
    fin.close();

    // iterate all synapses
    Json::Value synapses = json_reader_vals["data"];
    for (int i = 0; i < synapses.size(); ++i) {
        vector<unsigned int> constraint_list;

        Json::Value location = synapses[i]["T-bar"]["location"];
        if (!location.empty()) {
            int xloc = location[(unsigned int)(0)].asUInt();
            int yloc = location[(unsigned int)(1)].asUInt();
            int zloc = location[(unsigned int)(2)].asUInt();

            // determine label corresponding to point
            libdvid::tuple start; start.push_back(xloc);
            start.push_back(yloc); start.push_back(zloc);

            // retrieve volume
            libdvid::DVIDLabelPtr labels;
            dvid_node.get_volume_roi(argv[5], start, sizes, channels, labels);
            unsigned long long* ptr = (unsigned long long int*) labels->get_raw();
            unsigned long long label = *ptr;

            if (label) {
                constraint_list.push_back(label);
                counts[label]++;
            }
        }
        Json::Value psds = synapses[i]["partners"];
        for (int i = 0; i < psds.size(); ++i) {
            Json::Value location = psds[i]["location"];
            if (!location.empty()) {
                int xloc = location[(unsigned int)(0)].asUInt();
                int yloc = location[(unsigned int)(1)].asUInt();
                int zloc = location[(unsigned int)(2)].asUInt();

                // determine label corresponding to point
                libdvid::tuple start; start.push_back(xloc);
                start.push_back(yloc); start.push_back(zloc);

                // retrieve volume
                libdvid::DVIDLabelPtr labels;
                dvid_node.get_volume_roi(argv[5], start, sizes, channels, labels);
                unsigned long long* ptr = (unsigned long long int*) labels->get_raw();
                unsigned long long label = *ptr;

                if (label) {
                    constraint_list.push_back(label);
                    counts[label]++;
                }
            }
        }

        // load constraints for Tbar to PSD and PSD to PSD
        for (int it1 = 0; it1 < constraint_list.size(); ++it1) {
            for (int it2 = (it1+1); it2 < constraint_list.size(); ++it2) {
                if (constraint_list[it1] != constraint_list[it2]) {
                    partners[(constraint_list[it1])].insert((constraint_list[it2]));
                    partners[(constraint_list[it2])].insert((constraint_list[it1]));
                }
            }
        }
    }
    cout << "Finished reading all synapses" << endl;

    // load vertex list and data
    vector<libdvid::Vertex> vertices;
    vector<libdvid::BinaryDataPtr> properties;
    libdvid::VertexTransactions transaction_ids;

    // load property data for post
    for (unordered_map<unsigned long long, unsigned long long>::iterator iter =
            counts.begin(); iter != counts.end(); ++iter) {
        vertices.push_back(libdvid::Vertex(iter->first, 0));

        // set count and constraints
        unsigned long long num_partners = partners[iter->first].size();
        int total_size = num_partners + 2;
        assert(sizeof(unsigned long long) == 8);

        unsigned long long* data = new unsigned long long [total_size];

        int spot = 0;
        data[spot] = iter->second;
        ++spot;
        data[spot] = num_partners;
        ++spot;
        for (unordered_set<unsigned long long>::iterator iter2 =
            partners[iter->first].begin(); iter2 != partners[iter->first].end(); ++iter2) {
            data[spot] = *iter2;
            ++spot;
        }

        properties.push_back(libdvid::BinaryData::create_binary_data((char*) data,
                    total_size*8));

        delete []data;
    }
    cout << "Finished processing all constraints" << endl;

    // nominally use transaction protection to load data; this should be run by itself
    vector<libdvid::BinaryDataPtr> properties_dummy;
    // retrieve vertex transactions
    dvid_node.get_properties(graph_name, vertices, SYNAPSE_KEY,
            properties_dummy, transaction_ids);

    // set vertex transactions
    vector<libdvid::Vertex> leftover_vertices;
    dvid_node.set_properties(graph_name, vertices, SYNAPSE_KEY, properties,
            transaction_ids, leftover_vertices);

    assert(leftover_vertices.size() == 0);

    return 0;
}

<|endoftext|>


<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include<algorithm>
#include<iomanip>
#include"boost/algorithm/string.hpp"

#include"ork/color.hpp"
#include"ork/distribution.hpp"

#if ORK_USE_GLM
#include"glm/vec3.hpp"

namespace ork {

#if ORK_DEBUG
#define ORK_NEG_COLOR_CHECK(COLOR)\
if(COLOR.r < 0.f || COLOR.g < 0.f || COLOR.b < 0.f) {\
	ORK_THROW(ORK("Negative color"));\
}
#else
#define ORK_NEG_COLOR_CHECK(COLOR)
#endif

//Waiting for C++17
ORK_INLINE float clamp(const float val, const float min, const float max) {
	return std::min(std::max(val, min), max);
}

float to_hex_space(const color4&c, const float max, const float chroma) {
	/*
	Six vertices for hexagon
	Define periodic, circular space: red is 0, green is 2, blue is 4
	*/
	if(chroma <= 0.f) {
		return 0.f;//By convention, to avoid divide by 0;
	}
	else if(max <= c.r) {//The red third, rotate [+1, -1] about datum 0;
		const float hue = (c.g - c.b) / chroma;
		return hue >= 0.f ? hue : hue + 6.f;//Perdiodicity, stay in [0, 1]
	}
	else if(max <= c.g) {//The green third, rotate [+1, -1] about datum 2;
		return (c.b - c.r) / chroma + 2.f;
	}
	else {//max <= c.b //The blue third, rotate [+1, -1] about datum 4;
		return (c.r - c.g) / chroma + 4.f;
	}
}

float value_or_lightness(const float min, const float max, const color_space cs) {
	switch(cs) {
	case color_space::hsv:
		return max;
	case color_space::hsl:
		return (max + min)*0.5f;
	default:
		ORK_THROW(ORK("Invalid color space"));
	}
}
float calc_saturation(const float chroma, const float value_or_lightness, const color_space cs) {
	switch(cs) {
	case color_space::hsv:
		if(value_or_lightness <= 0.f) {
			return 0.f;
		}
		return chroma / value_or_lightness;//(max - min)/max
	case color_space::hsl:
		if(value_or_lightness <= 0.f || 1.f <= value_or_lightness) {
			return 0.f;
		}
		return chroma / (1.f - std::abs(2.f * value_or_lightness - 1.f));//(max - min)/(1 - |(max + min) - 1|)
	default:
		ORK_THROW(ORK("Invalid color space"));
	}
}

glm::vec3 calc_rgb(const float C, const float min, const float h_6) {
	const float X = C*(1.f - std::abs(std::fmod(h_6, 2.f) - 1.f));
	if(h_6 < 1.f) {
		return glm::vec3{C, X, 0.f}+min;
	}
	else if(h_6 < 2.f) {
		return glm::vec3{X, C, 0.f}+min;
	}
	else if(h_6 < 3.f) {
		return glm::vec3{0.f, C, X}+min;
	}
	else if(h_6 < 4.f) {
		return glm::vec3{0.f, X, C}+min;
	}
	else if(h_6 < 5.f) {
		return glm::vec3{X, 0.f, C}+min;
	}
	else {
		return glm::vec3{C, 0.f, X}+min;
	}
}

color4 truncate_hue(const color4&c, const color_space cs) {
	if(cs == color_space::rgb) {
		return c;//This call does not really make sense, but we allow it
	}
	color4 retval(c);
	if(std::min(c.g, c.b) <= 0.f) {//Saturation or bottom of cone, hue = 0 by convention
		retval.r = 0.f;
	}
	if(cs == color_space::hsl && c.b >= 1.0) {//Top of cone
		retval.r = 0.f;
	}
	if(retval.r >= 1.f) {
		retval.r -= 1.f;//Origin wraps to 0
	}
	return retval;
}

color4 truncate_saturation(const color4&c, const color_space cs) {
	if(cs == color_space::rgb) {
		return c;//This call does not really make sense, but we allow it
	}
	color4 retval(c);
	if(c.b <= 0.f) {//Saturation or bottom of cone, hue = 0 by convention
		retval.g = 0.f;
	}
	if(cs == color_space::hsl && c.b >= 1.0) {//Top of cone
		retval.g = 0.f;
	}
	return retval;
}

color4 truncate(const color4&c, const color_space cs) {
	return truncate_hue(truncate_saturation(c, cs), cs);
}

color4 convert(const color4&c, const color_space from_space, const color_space to_space) {
	/*
	RGB cube, HSV cylinder, HSL cone
	In short, turn the cube so 0,0,0 is at bottom and 1,1,1 is at top.
	The other 6 points of the cube project onto the corners of a hexagon.
	Rotate so that red is at 0 datum.
	See https://en.wikipedia.org/wiki/HSL_and_HSV for a good geometric description.
	*/
	if(from_space == to_space) {//A useful invariant below
		return c;
	}
	if(from_space == color_space::rgb) {
		const float min = std::min(c.r, std::min(c.g, c.b));
		const float max = std::max(c.r, std::max(c.g, c.b));
		const float chroma = max - min;//The normalized scale for color magnitudes

		const float hue = to_hex_space(c, max, chroma) / 6.f;//Normalize six-point space to unit interval
		const float val_light = value_or_lightness(min, max, to_space);
		const float saturation = calc_saturation(chroma, val_light, to_space);

		color4 retval{hue, saturation, val_light, c.a};//Debugging
		ORK_NEG_COLOR_CHECK(retval);
		return retval;
	}
	else {
		const bool is_hsv = from_space == color_space::hsv;//Otherwise HSL

		const float chroma = is_hsv
			? c.y*c.z//S*V
			: (1.f - std::abs(2.f*c.z - 1.f))*c.y//(1 - |2*L - 1|)*S
			;
		const float min = std::max(0.f, is_hsv
			? c.z - chroma
			: c.z - chroma*0.5f
		);
		if(to_space == color_space::rgb) {
			const float h_6 = c.x*6.f;//To hex coordinates
			const glm::vec3 rgb{calc_rgb(chroma, min, h_6)};
			color4 retval{rgb, c.a};//Debugging
			ORK_NEG_COLOR_CHECK(retval);
			return retval;
		}
		else {
			const float max = is_hsv
				? c.z
				: c.z + chroma*0.5f
				;
			const float val_light = value_or_lightness(min, max, to_space);
			const float saturation = calc_saturation(chroma, val_light, to_space);
			color4 retval{c.x, saturation, val_light, c.a};//Debugging
			ORK_NEG_COLOR_CHECK(retval);
			return retval;
		}
	}

}

ORK_ORK_API const color4 red = {1., 0., 0., 1.};
ORK_ORK_API const color4 green = {0., 1., 0., 1.};
ORK_ORK_API const color4 blue = {0., 0., 1., 1.};
ORK_ORK_API const color4 white = {1., 1., 1., 1.};

color4 normalized_lightness(const color4&c, const float lightness, const color_space cs) {
	color4 hsl = convert(c, cs, color_space::hsl);
	hsl.b = lightness;
	return convert(hsl, color_space::hsl, cs);
}
float luma(const color4&rgb) {
#if 0//luma 601 goes overboard; blue is clearly brightest
	return 0.30f*c.r + 0.59f*c.g + 0.11f*c.b;
#else
	return 0.3f*rgb.r + 0.5f*rgb.g + 0.2f*rgb.b;
#endif
}
color4 normalized_luma(const color4&c, const float lum, const color_space cs) {
	/*
	This is a simplified model using luma 601 coefficients https://en.wikipedia.org/wiki/HSL_and_HSV.
	Basically, yellow-green appears light and violet-blue appears dark.
	*/
	color4 rgb(convert(c, cs, color_space::rgb));
	if(rgb.r <= 0.f && rgb.g <= 0.f && rgb.b <= 0.f) {
		return convert(white*lum, color_space::rgb, cs);
	}
	float curr_luma = luma(rgb);
	while(std::abs(lum - curr_luma) > 0.02) {//Arbitrary magic number
		color4 hsl(convert(rgb, color_space::rgb, color_space::hsl));
		hsl.b = std::min(1.f, hsl.b*(1.f + 0.2f*(lum - curr_luma)));
		rgb = convert(hsl, color_space::hsl, color_space::rgb);
		curr_luma = luma(rgb);
	}
	return convert(rgb, color_space::rgb, cs);
}

color4 normalized_hue(const float value) {//Value is defined on [0, 1]
	/*
	This is waay simplified, and uses made-up triangle distributions.
	We multiply value by 1.5 instead of using thirds.
	Each color should be symmetrical and occupy 1.0 width.
	We narrow the green spectrum to 0.8.
	*/
	static ork::triangle_distribution<float>blue_l{-1.0f, -0.5f, 0.1f};//Periodicity
	static ork::triangle_distribution<float>red_l{-0.5f, 0.1f, 0.5f};//0.0 should be pure red
	static ork::triangle_distribution<float>green{0.1f, 0.5f, 0.9f};//0.5 is pure green
	static ork::triangle_distribution<float>blue_h{0.5f, 0.9f, 1.5f};//1.0 should be pure blue
	static ork::triangle_distribution<float>red_h{0.9f, 1.5f, 2.0f};//Periodicity

	const float rl = red_l(value);
	const float rh = red_h(value);
	const float g = green(value);
	const float bl = blue_l(value);
	const float bh = blue_h(value);
	const glm::dvec4 normed{rl + rh, g, bl + bh, 1.f};
	return normed;
}

color4 normalized_red_green(const float weight) {
	const float alpha = std::pow(std::max(0.f, std::min(1.f, weight)), 1.3f);
	return (1.f - alpha)*red + alpha*green;
}

std::vector<color4> contrast_array(const size_t size) {
	return contrast_array(size, 0.2f);
}
std::vector<color4>contrast_array(const size_t size, const float luma) {
	/*
	1.
	We want max difference between colors, garish is encouraged, so saturation is constant 100%.
	As a bonus there will be no grey that might be confused with the 'base' part.
	We are down to two dimensions.
	2.
	Colors with equal contrast with the background are percieved with equal importance.
	We want equal importance and assume a white backgrond.
	If only this meant constant lightness the problem would be reduced to one dimension, hue.
	3.
	Colors in proximity are perceived as more different.
	Humans process difference more easily bwtween colors in close proximity if variation is smallish.
	We can't account for spatial proximity within this function interface, but it is something to think about.
	*/
	std::vector<color4>retval;
	LOOPI(size) {
		const float val = float(i) / float(size - 1);
		const color4 hue(normalized_hue(val));
		const color4 luma(normalized_luma(hue, luma, color_space::rgb));
		retval.push_back(luma);
	}
	return std::move(retval);
}

string to_hex(const color4&c, const color_space cs) {
	const color4 rgb(convert(c, cs, color_space::rgb));
	ork::o_string_stream stream;
	stream	<< std::setfill(ORK('0')) << std::hex
			<< std::setw(2) << short(rgb.r*255.f) << std::setw(2) << short(rgb.g*255.f) << std::setw(2) << short(rgb.b*255.f) << std::setw(2) << short(rgb.a*255.f);
	return boost::to_upper_copy(stream.str());
}

}//namespace ork

namespace glm {

ork::o_stream&operator<<(ork::o_stream&stream, const ork::color4&c) {
	stream << ORK("(") << c.r << ORK(", ") << c.g << ORK(", ") << c.b << ORK(", ") << c.a << ORK(")");
	return stream;
}

}

#endif//ORK_USE_GLM
<commit_msg>Further reduced difference for luma<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include<algorithm>
#include<iomanip>
#include"boost/algorithm/string.hpp"

#include"ork/color.hpp"
#include"ork/distribution.hpp"

#if ORK_USE_GLM
#include"glm/vec3.hpp"

namespace ork {

#if ORK_DEBUG
#define ORK_NEG_COLOR_CHECK(COLOR)\
if(COLOR.r < 0.f || COLOR.g < 0.f || COLOR.b < 0.f) {\
	ORK_THROW(ORK("Negative color"));\
}
#else
#define ORK_NEG_COLOR_CHECK(COLOR)
#endif

//Waiting for C++17
ORK_INLINE float clamp(const float val, const float min, const float max) {
	return std::min(std::max(val, min), max);
}

float to_hex_space(const color4&c, const float max, const float chroma) {
	/*
	Six vertices for hexagon
	Define periodic, circular space: red is 0, green is 2, blue is 4
	*/
	if(chroma <= 0.f) {
		return 0.f;//By convention, to avoid divide by 0;
	}
	else if(max <= c.r) {//The red third, rotate [+1, -1] about datum 0;
		const float hue = (c.g - c.b) / chroma;
		return hue >= 0.f ? hue : hue + 6.f;//Perdiodicity, stay in [0, 1]
	}
	else if(max <= c.g) {//The green third, rotate [+1, -1] about datum 2;
		return (c.b - c.r) / chroma + 2.f;
	}
	else {//max <= c.b //The blue third, rotate [+1, -1] about datum 4;
		return (c.r - c.g) / chroma + 4.f;
	}
}

float value_or_lightness(const float min, const float max, const color_space cs) {
	switch(cs) {
	case color_space::hsv:
		return max;
	case color_space::hsl:
		return (max + min)*0.5f;
	default:
		ORK_THROW(ORK("Invalid color space"));
	}
}
float calc_saturation(const float chroma, const float value_or_lightness, const color_space cs) {
	switch(cs) {
	case color_space::hsv:
		if(value_or_lightness <= 0.f) {
			return 0.f;
		}
		return chroma / value_or_lightness;//(max - min)/max
	case color_space::hsl:
		if(value_or_lightness <= 0.f || 1.f <= value_or_lightness) {
			return 0.f;
		}
		return chroma / (1.f - std::abs(2.f * value_or_lightness - 1.f));//(max - min)/(1 - |(max + min) - 1|)
	default:
		ORK_THROW(ORK("Invalid color space"));
	}
}

glm::vec3 calc_rgb(const float C, const float min, const float h_6) {
	const float X = C*(1.f - std::abs(std::fmod(h_6, 2.f) - 1.f));
	if(h_6 < 1.f) {
		return glm::vec3{C, X, 0.f}+min;
	}
	else if(h_6 < 2.f) {
		return glm::vec3{X, C, 0.f}+min;
	}
	else if(h_6 < 3.f) {
		return glm::vec3{0.f, C, X}+min;
	}
	else if(h_6 < 4.f) {
		return glm::vec3{0.f, X, C}+min;
	}
	else if(h_6 < 5.f) {
		return glm::vec3{X, 0.f, C}+min;
	}
	else {
		return glm::vec3{C, 0.f, X}+min;
	}
}

color4 truncate_hue(const color4&c, const color_space cs) {
	if(cs == color_space::rgb) {
		return c;//This call does not really make sense, but we allow it
	}
	color4 retval(c);
	if(std::min(c.g, c.b) <= 0.f) {//Saturation or bottom of cone, hue = 0 by convention
		retval.r = 0.f;
	}
	if(cs == color_space::hsl && c.b >= 1.0) {//Top of cone
		retval.r = 0.f;
	}
	if(retval.r >= 1.f) {
		retval.r -= 1.f;//Origin wraps to 0
	}
	return retval;
}

color4 truncate_saturation(const color4&c, const color_space cs) {
	if(cs == color_space::rgb) {
		return c;//This call does not really make sense, but we allow it
	}
	color4 retval(c);
	if(c.b <= 0.f) {//Saturation or bottom of cone, hue = 0 by convention
		retval.g = 0.f;
	}
	if(cs == color_space::hsl && c.b >= 1.0) {//Top of cone
		retval.g = 0.f;
	}
	return retval;
}

color4 truncate(const color4&c, const color_space cs) {
	return truncate_hue(truncate_saturation(c, cs), cs);
}

color4 convert(const color4&c, const color_space from_space, const color_space to_space) {
	/*
	RGB cube, HSV cylinder, HSL cone
	In short, turn the cube so 0,0,0 is at bottom and 1,1,1 is at top.
	The other 6 points of the cube project onto the corners of a hexagon.
	Rotate so that red is at 0 datum.
	See https://en.wikipedia.org/wiki/HSL_and_HSV for a good geometric description.
	*/
	if(from_space == to_space) {//A useful invariant below
		return c;
	}
	if(from_space == color_space::rgb) {
		const float min = std::min(c.r, std::min(c.g, c.b));
		const float max = std::max(c.r, std::max(c.g, c.b));
		const float chroma = max - min;//The normalized scale for color magnitudes

		const float hue = to_hex_space(c, max, chroma) / 6.f;//Normalize six-point space to unit interval
		const float val_light = value_or_lightness(min, max, to_space);
		const float saturation = calc_saturation(chroma, val_light, to_space);

		color4 retval{hue, saturation, val_light, c.a};//Debugging
		ORK_NEG_COLOR_CHECK(retval);
		return retval;
	}
	else {
		const bool is_hsv = from_space == color_space::hsv;//Otherwise HSL

		const float chroma = is_hsv
			? c.y*c.z//S*V
			: (1.f - std::abs(2.f*c.z - 1.f))*c.y//(1 - |2*L - 1|)*S
			;
		const float min = std::max(0.f, is_hsv
			? c.z - chroma
			: c.z - chroma*0.5f
		);
		if(to_space == color_space::rgb) {
			const float h_6 = c.x*6.f;//To hex coordinates
			const glm::vec3 rgb{calc_rgb(chroma, min, h_6)};
			color4 retval{rgb, c.a};//Debugging
			ORK_NEG_COLOR_CHECK(retval);
			return retval;
		}
		else {
			const float max = is_hsv
				? c.z
				: c.z + chroma*0.5f
				;
			const float val_light = value_or_lightness(min, max, to_space);
			const float saturation = calc_saturation(chroma, val_light, to_space);
			color4 retval{c.x, saturation, val_light, c.a};//Debugging
			ORK_NEG_COLOR_CHECK(retval);
			return retval;
		}
	}

}

ORK_ORK_API const color4 red = {1., 0., 0., 1.};
ORK_ORK_API const color4 green = {0., 1., 0., 1.};
ORK_ORK_API const color4 blue = {0., 0., 1., 1.};
ORK_ORK_API const color4 white = {1., 1., 1., 1.};

color4 normalized_lightness(const color4&c, const float lightness, const color_space cs) {
	color4 hsl = convert(c, cs, color_space::hsl);
	hsl.b = lightness;
	return convert(hsl, color_space::hsl, cs);
}
float luma(const color4&rgb) {
#if 0//luma 601 goes overboard; blue is clearly brightest
	return 0.30f*c.r + 0.59f*c.g + 0.11f*c.b;
#elif 0//This was a little dark in the red-green range
	return 0.3f*rgb.r + 0.5f*rgb.g + 0.2f*rgb.b;
#else
	return 0.32f*rgb.r + 0.46f*rgb.g + 0.22f*rgb.b;
#endif
}
color4 normalized_luma(const color4&c, const float lum, const color_space cs) {
	/*
	This is a simplified model using luma 601 coefficients https://en.wikipedia.org/wiki/HSL_and_HSV.
	Basically, yellow-green appears light and violet-blue appears dark.
	*/
	color4 rgb(convert(c, cs, color_space::rgb));
	if(rgb.r <= 0.f && rgb.g <= 0.f && rgb.b <= 0.f) {
		return convert(white*lum, color_space::rgb, cs);
	}
	float curr_luma = luma(rgb);
	while(std::abs(lum - curr_luma) > 0.02) {//Arbitrary magic number
		color4 hsl(convert(rgb, color_space::rgb, color_space::hsl));
		hsl.b = std::min(1.f, hsl.b*(1.f + 0.2f*(lum - curr_luma)));
		rgb = convert(hsl, color_space::hsl, color_space::rgb);
		curr_luma = luma(rgb);
	}
	return convert(rgb, color_space::rgb, cs);
}

color4 normalized_hue(const float value) {//Value is defined on [0, 1]
	/*
	This is waay simplified, and uses made-up triangle distributions.
	We multiply value by 1.5 instead of using thirds.
	Each color should be symmetrical and occupy 1.0 width.
	We narrow the green spectrum to 0.8.
	*/
	static ork::triangle_distribution<float>blue_l{-1.0f, -0.5f, 0.1f};//Periodicity
	static ork::triangle_distribution<float>red_l{-0.5f, 0.1f, 0.5f};//0.0 should be pure red
	static ork::triangle_distribution<float>green{0.1f, 0.5f, 0.9f};//0.5 is pure green
	static ork::triangle_distribution<float>blue_h{0.5f, 0.9f, 1.5f};//1.0 should be pure blue
	static ork::triangle_distribution<float>red_h{0.9f, 1.5f, 2.0f};//Periodicity

	const float rl = red_l(value);
	const float rh = red_h(value);
	const float g = green(value);
	const float bl = blue_l(value);
	const float bh = blue_h(value);
	const glm::dvec4 normed{rl + rh, g, bl + bh, 1.f};
	return normed;
}

color4 normalized_red_green(const float weight) {
	const float alpha = std::pow(std::max(0.f, std::min(1.f, weight)), 1.3f);
	return (1.f - alpha)*red + alpha*green;
}

std::vector<color4> contrast_array(const size_t size) {
	return contrast_array(size, 0.2f);
}
std::vector<color4>contrast_array(const size_t size, const float luma) {
	/*
	1.
	We want max difference between colors, garish is encouraged, so saturation is constant 100%.
	As a bonus there will be no grey that might be confused with the 'base' part.
	We are down to two dimensions.
	2.
	Colors with equal contrast with the background are percieved with equal importance.
	We want equal importance and assume a white backgrond.
	If only this meant constant lightness the problem would be reduced to one dimension, hue.
	3.
	Colors in proximity are perceived as more different.
	Humans process difference more easily bwtween colors in close proximity if variation is smallish.
	We can't account for spatial proximity within this function interface, but it is something to think about.
	*/
	std::vector<color4>retval;
	LOOPI(size) {
		const float val = float(i) / float(size - 1);
		const color4 hue(normalized_hue(val));
		const color4 luma(normalized_luma(hue, luma, color_space::rgb));
		retval.push_back(luma);
	}
	return std::move(retval);
}

string to_hex(const color4&c, const color_space cs) {
	const color4 rgb(convert(c, cs, color_space::rgb));
	ork::o_string_stream stream;
	stream	<< std::setfill(ORK('0')) << std::hex
			<< std::setw(2) << short(rgb.r*255.f) << std::setw(2) << short(rgb.g*255.f) << std::setw(2) << short(rgb.b*255.f) << std::setw(2) << short(rgb.a*255.f);
	return boost::to_upper_copy(stream.str());
}

}//namespace ork

namespace glm {

ork::o_stream&operator<<(ork::o_stream&stream, const ork::color4&c) {
	stream << ORK("(") << c.r << ORK(", ") << c.g << ORK(", ") << c.b << ORK(", ") << c.a << ORK(")");
	return stream;
}

}

#endif//ORK_USE_GLM
<|endoftext|>


<commit_before>/*
 * Copyright 2011, Tim Branyen @tbranyen <tim@tabdeveloper.com>
 * Dual licensed under the MIT and GPL licenses.
 */

#include <string.h>
#include <v8.h>
#include <node.h>

#include "../vendor/libgit2/include/git2.h"
#include "cvv8/v8-convert.hpp"

#include "../include/reference.h"
#include "../include/sig.h"
#include "../include/repo.h"
#include "../include/oid.h"
#include "../include/tree.h"
#include "../include/commit.h"

using namespace v8;
using namespace node;

void GitCommit::Initialize(Handle<Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);

  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->SetClassName(String::NewSymbol("Commit"));

  NODE_SET_PROTOTYPE_METHOD(tpl, "lookup", Lookup);
  NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close);
  NODE_SET_PROTOTYPE_METHOD(tpl, "id", Id);
  NODE_SET_PROTOTYPE_METHOD(tpl, "messageShort", MessageShort);
  NODE_SET_PROTOTYPE_METHOD(tpl, "message", Message);
  NODE_SET_PROTOTYPE_METHOD(tpl, "time", Time);
  NODE_SET_PROTOTYPE_METHOD(tpl, "timeOffset", TimeOffset);
  NODE_SET_PROTOTYPE_METHOD(tpl, "author", Author);
  NODE_SET_PROTOTYPE_METHOD(tpl, "tree", Tree);
  NODE_SET_PROTOTYPE_METHOD(tpl, "parentCount", ParentCount);
  NODE_SET_PROTOTYPE_METHOD(tpl, "parent", Parent);
  NODE_SET_PROTOTYPE_METHOD(tpl, "parentSync", ParentSync);

  constructor_template = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Commit"), constructor_template);
}

git_commit* GitCommit::GetValue() {
  return this->commit;
}

void GitCommit::SetValue(git_commit* commit) {
  this->commit = commit;
}

int GitCommit::Lookup(git_repository* repo, git_oid* oid) {
  int err = git_commit_lookup(&this->commit, repo, oid);

  return err;
}

void GitCommit::Close() {
  git_commit_close(this->commit);
  this->commit = NULL;
}

const git_oid* GitCommit::Id() {
  return git_commit_id(this->commit);
}

const char* GitCommit::MessageShort() {
  return "";
  //return git_commit_message_short(this->commit);
}

const char* GitCommit::Message() {
  return git_commit_message(this->commit);
}

time_t GitCommit::Time() {
  return git_commit_time(this->commit);
}

int GitCommit::TimeOffset() {
  return git_commit_time_offset(this->commit);
}

const git_signature* GitCommit::Committer() {
  return git_commit_author(this->commit);
}

const git_signature* GitCommit::Author() {
  return git_commit_author(this->commit);
}

int GitCommit::Tree(git_tree** tree) {
  return git_commit_tree(tree, this->commit);
}

unsigned int GitCommit::ParentCount() {
  return git_commit_parentcount(this->commit);
}

int GitCommit::Parent(git_commit** commit, int pos) {
  return git_commit_parent(commit, this->commit, pos);
}

Handle<Value> GitCommit::New(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = new GitCommit();

  commit->Wrap(args.This());

  return scope.Close(args.This());
}

Handle<Value> GitCommit::NewInstance() {
  HandleScope scope;

  Local<Object> instance = constructor_template->NewInstance();

  return scope.Close(instance);
}

Handle<Value> GitCommit::Lookup(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());
  Local<Function> callback;

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Repo is required and must be an Object.")));
  }

  if(args.Length() == 1 || !args[1]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Oid is required and must be an Object.")));
  }

  if(args.Length() == 2 || !args[2]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  callback = Local<Function>::Cast(args[2]);

  lookup_request *ar = new lookup_request();
  ar->commit = commit;
  ar->repo = ObjectWrap::Unwrap<GitRepo>(args[0]->ToObject());
  ar->oid = ObjectWrap::Unwrap<GitOid>(args[1]->ToObject());
  ar->callback = Persistent<Function>::New(callback);

  commit->Ref();

  uv_work_t *req = new uv_work_t;
  req->data = ar;
  uv_queue_work(uv_default_loop(), req, LookupWork, LookupAfterWork);

  return scope.Close( Undefined() );
}

void GitCommit::LookupWork(uv_work_t *req) {
  lookup_request *ar = static_cast<lookup_request *>(req->data);

  git_oid oid = ar->oid->GetValue();
  ar->err = ar->commit->Lookup(ar->repo->GetValue(), &oid);
}

void GitCommit::LookupAfterWork(uv_work_t *req) {
  HandleScope scope;

  lookup_request *ar = static_cast<lookup_request *>(req->data);
  delete req;

  ar->commit->Unref();

  Handle<Value> argv[1];
  argv[0] = Integer::New(ar->err);

  TryCatch try_catch;

  ar->callback->Call(Context::GetCurrent()->Global(), 1, argv);

  if(try_catch.HasCaught()) {
    FatalException(try_catch);
  }

  ar->callback.Dispose();

  delete ar;
}

Handle<Value> GitCommit::Close(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());
  commit->Close();

  return scope.Close(Undefined());
}

Handle<Value> GitCommit::Id(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Oid is required and must be an Object.")));
  }

  GitOid *oid = ObjectWrap::Unwrap<GitOid>(args[0]->ToObject());

  oid->SetValue(*const_cast<git_oid *>(commit->Id()));

  return scope.Close(Undefined());
}

Handle<Value> GitCommit::MessageShort(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close( String::New(commit->MessageShort()) );
}

Handle<Value> GitCommit::Message(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close(String::New(commit->Message()));
}

Handle<Value> GitCommit::Time(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close( Integer::New(commit->Time()) );
}

Handle<Value> GitCommit::TimeOffset(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close( Integer::New(commit->TimeOffset()) );
}

Handle<Value> GitCommit::Committer(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Signature is required and must be an Object.")));
  }

  GitSig *sig = ObjectWrap::Unwrap<GitSig>(args[0]->ToObject());

  sig->SetValue(const_cast<git_signature *>(commit->Committer()));

  return scope.Close( Undefined() );
}

Handle<Value> GitCommit::Author(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Signature is required and must be an Object.")));
  }

  GitSig *sig = ObjectWrap::Unwrap<GitSig>(args[0]->ToObject());

  sig->SetValue(const_cast<git_signature *>(commit->Author()));

  return scope.Close( Undefined() );
}

Handle<Value> GitCommit::Tree(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Tree is required and must be an Object.")));
  }

  GitTree* g_tree = ObjectWrap::Unwrap<GitTree>(args[0]->ToObject());

  git_tree* tree;
  int err = commit->Tree(&tree);
  g_tree->SetValue(tree);

  return scope.Close( Integer::New(err) );
}

Handle<Value> GitCommit::ParentCount(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  unsigned int count = commit->ParentCount();

  return scope.Close( Integer::New(count) );
}

Handle<Value> GitCommit::ParentSync(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsNumber()) {
    return ThrowException(Exception::Error(String::New("Position must be a Number.")));
  }

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  git_commit *parentCommitValue ;
  int errorCode = git_commit_parent(&parentCommitValue, commit->commit, args[0]->ToInteger()->Value());

  if (errorCode) {
    return ThrowException(Exception::Error(String::New(git_lasterror())));
  }

  Local<Object> parent = GitCommit::constructor_template->NewInstance();
  GitCommit *parentCommit = ObjectWrap::Unwrap<GitCommit>(parent);
  parentCommit->SetValue(parentCommitValue);

  return scope.Close(parent);
}

Handle<Value> GitCommit::Parent(const Arguments& args) {
  HandleScope scope;

  if(args.Length() != 2) {
    return ThrowException(Exception::Error(String::New("Position and callback are required")));
  }

  if(!args[0]->IsNumber()) {
    return ThrowException(Exception::Error(String::New("Position is required and must be a Number.")));
  }

  if(!args[1]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  Local<Function> callback = Local<Function>::Cast(args[1]);

  ParentBaton* baton = new ParentBaton();
  baton->request.data = baton;
  baton->commit =  ObjectWrap::Unwrap<GitCommit>(args.This());
  baton->commit->Ref();
  baton->index = args[0]->ToInteger()->Value();
  baton->callback = Persistent<Function>::New(callback);

  uv_queue_work(uv_default_loop(), &baton->request, ParentWork, ParentAfterWork);

 return Undefined();
}

void GitCommit::ParentWork(uv_work_t* req) {
  ParentBaton* baton = static_cast<ParentBaton*>(req->data);

  baton->rawParentCommit = NULL;
  baton->errorCode = git_commit_parent(&baton->rawParentCommit, baton->commit->commit, baton->index);

  if (baton->errorCode) {
    baton->errorMessage = git_lasterror();
  }
}

void GitCommit::ParentAfterWork(uv_work_t* req) {
  HandleScope scope;

  ParentBaton* baton = static_cast<ParentBaton* >(req->data);
  delete req;

  if (baton->errorCode) {
    Local<Value> argv[1] = {
      Exception::Error(String::New(baton->errorMessage))
    };

    TryCatch try_catch;

    baton->callback->Call(Context::GetCurrent()->Global(), 1, argv);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
  } else {

    Local<Object> parent = GitCommit::constructor_template->NewInstance();
    GitCommit *parentCommit = ObjectWrap::Unwrap<GitCommit>(parent);
    parentCommit->SetValue(baton->rawParentCommit);

    Handle<Value> argv[2] = {
      Local<Value>::New(Null()),
      parent
    };

    TryCatch try_catch;
    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
  }
  baton->commit->Unref();
  delete baton;
}

Persistent<Function> GitCommit::constructor_template;
<commit_msg>Fixed malloc error<commit_after>/*
 * Copyright 2011, Tim Branyen @tbranyen <tim@tabdeveloper.com>
 * Dual licensed under the MIT and GPL licenses.
 */

#include <string.h>
#include <v8.h>
#include <node.h>

#include "../vendor/libgit2/include/git2.h"
#include "cvv8/v8-convert.hpp"

#include "../include/reference.h"
#include "../include/sig.h"
#include "../include/repo.h"
#include "../include/oid.h"
#include "../include/tree.h"
#include "../include/commit.h"

using namespace v8;
using namespace node;

void GitCommit::Initialize(Handle<Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);

  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->SetClassName(String::NewSymbol("Commit"));

  NODE_SET_PROTOTYPE_METHOD(tpl, "lookup", Lookup);
  NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close);
  NODE_SET_PROTOTYPE_METHOD(tpl, "id", Id);
  NODE_SET_PROTOTYPE_METHOD(tpl, "messageShort", MessageShort);
  NODE_SET_PROTOTYPE_METHOD(tpl, "message", Message);
  NODE_SET_PROTOTYPE_METHOD(tpl, "time", Time);
  NODE_SET_PROTOTYPE_METHOD(tpl, "timeOffset", TimeOffset);
  NODE_SET_PROTOTYPE_METHOD(tpl, "author", Author);
  NODE_SET_PROTOTYPE_METHOD(tpl, "tree", Tree);
  NODE_SET_PROTOTYPE_METHOD(tpl, "parentCount", ParentCount);
  NODE_SET_PROTOTYPE_METHOD(tpl, "parent", Parent);
  NODE_SET_PROTOTYPE_METHOD(tpl, "parentSync", ParentSync);

  constructor_template = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Commit"), constructor_template);
}

git_commit* GitCommit::GetValue() {
  return this->commit;
}

void GitCommit::SetValue(git_commit* commit) {
  this->commit = commit;
}

int GitCommit::Lookup(git_repository* repo, git_oid* oid) {
  int err = git_commit_lookup(&this->commit, repo, oid);

  return err;
}

void GitCommit::Close() {
  git_commit_close(this->commit);
  this->commit = NULL;
}

const git_oid* GitCommit::Id() {
  return git_commit_id(this->commit);
}

const char* GitCommit::MessageShort() {
  return "";
  //return git_commit_message_short(this->commit);
}

const char* GitCommit::Message() {
  return git_commit_message(this->commit);
}

time_t GitCommit::Time() {
  return git_commit_time(this->commit);
}

int GitCommit::TimeOffset() {
  return git_commit_time_offset(this->commit);
}

const git_signature* GitCommit::Committer() {
  return git_commit_author(this->commit);
}

const git_signature* GitCommit::Author() {
  return git_commit_author(this->commit);
}

int GitCommit::Tree(git_tree** tree) {
  return git_commit_tree(tree, this->commit);
}

unsigned int GitCommit::ParentCount() {
  return git_commit_parentcount(this->commit);
}

int GitCommit::Parent(git_commit** commit, int pos) {
  return git_commit_parent(commit, this->commit, pos);
}

Handle<Value> GitCommit::New(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = new GitCommit();

  commit->Wrap(args.This());

  return scope.Close(args.This());
}

Handle<Value> GitCommit::NewInstance() {
  HandleScope scope;

  Local<Object> instance = constructor_template->NewInstance();

  return scope.Close(instance);
}

Handle<Value> GitCommit::Lookup(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());
  Local<Function> callback;

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Repo is required and must be an Object.")));
  }

  if(args.Length() == 1 || !args[1]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Oid is required and must be an Object.")));
  }

  if(args.Length() == 2 || !args[2]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  callback = Local<Function>::Cast(args[2]);

  lookup_request *ar = new lookup_request();
  ar->commit = commit;
  ar->repo = ObjectWrap::Unwrap<GitRepo>(args[0]->ToObject());
  ar->oid = ObjectWrap::Unwrap<GitOid>(args[1]->ToObject());
  ar->callback = Persistent<Function>::New(callback);

  commit->Ref();

  uv_work_t *req = new uv_work_t;
  req->data = ar;
  uv_queue_work(uv_default_loop(), req, LookupWork, LookupAfterWork);

  return scope.Close( Undefined() );
}

void GitCommit::LookupWork(uv_work_t *req) {
  lookup_request *ar = static_cast<lookup_request *>(req->data);

  git_oid oid = ar->oid->GetValue();
  ar->err = ar->commit->Lookup(ar->repo->GetValue(), &oid);
}

void GitCommit::LookupAfterWork(uv_work_t *req) {
  HandleScope scope;

  lookup_request *ar = static_cast<lookup_request *>(req->data);
  delete req;

  ar->commit->Unref();

  Handle<Value> argv[1];
  argv[0] = Integer::New(ar->err);

  TryCatch try_catch;

  ar->callback->Call(Context::GetCurrent()->Global(), 1, argv);

  if(try_catch.HasCaught()) {
    FatalException(try_catch);
  }

  ar->callback.Dispose();

  delete ar;
}

Handle<Value> GitCommit::Close(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());
  commit->Close();

  return scope.Close(Undefined());
}

Handle<Value> GitCommit::Id(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Oid is required and must be an Object.")));
  }

  GitOid *oid = ObjectWrap::Unwrap<GitOid>(args[0]->ToObject());

  oid->SetValue(*const_cast<git_oid *>(commit->Id()));

  return scope.Close(Undefined());
}

Handle<Value> GitCommit::MessageShort(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close( String::New(commit->MessageShort()) );
}

Handle<Value> GitCommit::Message(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close(String::New(commit->Message()));
}

Handle<Value> GitCommit::Time(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close( Integer::New(commit->Time()) );
}

Handle<Value> GitCommit::TimeOffset(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  return scope.Close( Integer::New(commit->TimeOffset()) );
}

Handle<Value> GitCommit::Committer(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Signature is required and must be an Object.")));
  }

  GitSig *sig = ObjectWrap::Unwrap<GitSig>(args[0]->ToObject());

  sig->SetValue(const_cast<git_signature *>(commit->Committer()));

  return scope.Close( Undefined() );
}

Handle<Value> GitCommit::Author(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Signature is required and must be an Object.")));
  }

  GitSig *sig = ObjectWrap::Unwrap<GitSig>(args[0]->ToObject());

  sig->SetValue(const_cast<git_signature *>(commit->Author()));

  return scope.Close( Undefined() );
}

Handle<Value> GitCommit::Tree(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  if(args.Length() == 0 || !args[0]->IsObject()) {
    return ThrowException(Exception::Error(String::New("Tree is required and must be an Object.")));
  }

  GitTree* g_tree = ObjectWrap::Unwrap<GitTree>(args[0]->ToObject());

  git_tree* tree;
  int err = commit->Tree(&tree);
  g_tree->SetValue(tree);

  return scope.Close( Integer::New(err) );
}

Handle<Value> GitCommit::ParentCount(const Arguments& args) {
  HandleScope scope;

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  unsigned int count = commit->ParentCount();

  return scope.Close( Integer::New(count) );
}

Handle<Value> GitCommit::ParentSync(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsNumber()) {
    return ThrowException(Exception::Error(String::New("Position must be a Number.")));
  }

  GitCommit *commit = ObjectWrap::Unwrap<GitCommit>(args.This());

  git_commit *parentCommitValue ;
  int errorCode = git_commit_parent(&parentCommitValue, commit->commit, args[0]->ToInteger()->Value());

  if (errorCode) {
    return ThrowException(Exception::Error(String::New(git_lasterror())));
  }

  Local<Object> parent = GitCommit::constructor_template->NewInstance();
  GitCommit *parentCommit = ObjectWrap::Unwrap<GitCommit>(parent);
  parentCommit->SetValue(parentCommitValue);

  return scope.Close(parent);
}

Handle<Value> GitCommit::Parent(const Arguments& args) {
  HandleScope scope;

  if(args.Length() != 2) {
    return ThrowException(Exception::Error(String::New("Position and callback are required")));
  }

  if(!args[0]->IsNumber()) {
    return ThrowException(Exception::Error(String::New("Position is required and must be a Number.")));
  }

  if(!args[1]->IsFunction()) {
    return ThrowException(Exception::Error(String::New("Callback is required and must be a Function.")));
  }

  Local<Function> callback = Local<Function>::Cast(args[1]);

  ParentBaton* baton = new ParentBaton();
  baton->request.data = baton;
  baton->commit =  ObjectWrap::Unwrap<GitCommit>(args.This());
  baton->commit->Ref();
  baton->index = args[0]->ToInteger()->Value();
  baton->callback = Persistent<Function>::New(callback);

  uv_queue_work(uv_default_loop(), &baton->request, ParentWork, ParentAfterWork);

 return Undefined();
}

void GitCommit::ParentWork(uv_work_t* req) {
  ParentBaton* baton = static_cast<ParentBaton*>(req->data);

  baton->rawParentCommit = NULL;
  baton->errorCode = git_commit_parent(&baton->rawParentCommit, baton->commit->commit, baton->index);

  if (baton->errorCode) {
    baton->errorMessage = git_lasterror();
  }
}

void GitCommit::ParentAfterWork(uv_work_t* req) {
  HandleScope scope;

  ParentBaton* baton = static_cast<ParentBaton* >(req->data);
  delete req;

  if (baton->errorCode) {
    Local<Value> argv[1] = {
      Exception::Error(String::New(baton->errorMessage))
    };

    TryCatch try_catch;

    baton->callback->Call(Context::GetCurrent()->Global(), 1, argv);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
  } else {

    Local<Object> parent = GitCommit::constructor_template->NewInstance();
    GitCommit *parentCommit = ObjectWrap::Unwrap<GitCommit>(parent);
    parentCommit->SetValue(baton->rawParentCommit);

    Handle<Value> argv[2] = {
      Local<Value>::New(Null()),
      parent
    };

    TryCatch try_catch;
    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);
    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
  }
  baton->commit->Unref();
}

Persistent<Function> GitCommit::constructor_template;
<|endoftext|>