<commit_before>/*
 * Copyright (C) 2020 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "seastarx.hh"
#include "log.hh"
#include "auth/role_manager.hh"
#include "auth/authenticated_user.hh"
#include <seastar/core/sstring.hh>
#include <seastar/core/distributed.hh>
#include "auth/service.hh"
#include "service/storage_service.hh"
#include <map>
#include <unordered_set>
#include "qos_common.hh"

namespace db {
    class system_distributed_keyspace;
}
namespace qos {
/**
 *  a structure to hold a service level
 *  data and configuration.
 */
struct service_level {
     service_level_options slo;
     bool marked_for_deletion;
     bool is_static;
};

/**
 *  The service_level_controller class is an implementation of the service level
 *  controller design.
 *  It is logically divided into 2 parts:
 *      1. Global controller which is responsible for all of the data and plumbing
 *      manipulation.
 *      2. Local controllers that act upon the data and facilitates execution in
 *      the service level context
 */
class service_level_controller : public peering_sharded_service<service_level_controller> {
public:
    class service_level_distributed_data_accessor {
    public:
        virtual future<qos::service_levels_info> get_service_levels() const = 0;
        virtual future<qos::service_levels_info> get_service_level(sstring service_level_name) const = 0;
        virtual future<> set_service_level(sstring service_level_name, qos::service_level_options slo) const = 0;
        virtual future<> drop_service_level(sstring service_level_name) const = 0;
    };
    using service_level_distributed_data_accessor_ptr = ::shared_ptr<service_level_distributed_data_accessor>;
private:
    struct global_controller_data {
        service_levels_info  static_configurations{};
        int schedg_group_cnt = 0;
        int io_priority_cnt = 0;
        service_level_options default_service_level_config;
        // The below future is used to serialize work so no reordering can occur.
        // This is needed so for example: delete(x), add(x) will not reverse yielding
        // a completely different result than the one intended.
        future<> work_future = make_ready_future();
        semaphore notifications_serializer = semaphore(1);
        future<> distributed_data_update = make_ready_future();
        abort_source dist_data_update_aborter;
    };

    std::unique_ptr<global_controller_data> _global_controller_db;

    static constexpr shard_id global_controller = 0;

    std::map<sstring, service_level> _service_levels_db;
    std::unordered_map<sstring, sstring> _role_to_service_level;
    service_level _default_service_level;
    service_level_distributed_data_accessor_ptr _sl_data_accessor;
    sharded<auth::service>& _auth_service;
public:
    service_level_controller(sharded<auth::service>& auth_service, service_level_options default_service_level_config);

    /**
     * this function must be called *once* from any shard before any other functions are called.
     * No other function should be called before the future returned by the function is resolved.
     * @return a future that resolves when the initialization is over.
     */
    future<> start();

    void set_distributed_data_accessor(service_level_distributed_data_accessor_ptr sl_data_accessor);

    /**
     *  Adds a service level configuration if it doesn't exists, and updates
     *  an the existing one if it does exist.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param slo - the service level configuration
     * @param is_static - is this configuration static or not
     */
    future<> add_service_level(sstring name, service_level_options slo, bool is_static = false);

    /**
     *  Removes a service level configuration if it exists.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param remove_static - indicates if it is a removal of a static configuration
     * or not.
     */
    future<> remove_service_level(sstring name, bool remove_static);

    /**
     * stops the distributed updater
     * @return a future that is resolved when the updates stopped
     */
    future<> drain();

    /**
     * stops all ongoing operations if exists
     * @return a future that is resolved when all operations has stopped
     */
    future<> stop();

    /**
     * this is an executor of a function with arguments under a service level
     * that corresponds to a given user.
     * @param usr - the user for determining the service level
     * @param func - the function to be executed
     * @return a future that is resolved when the function's operation is resolved
     * (if it returns a future). or a ready future containing the returned value
     * from the function/
     */
    template <typename Ret>
    futurize_t<Ret> with_user_service_level(shared_ptr<auth::authenticated_user> usr, noncopyable_function<Ret()> func) {
        if (usr) {
            auth::service& ser = _auth_service.local();
            return auth::get_roles(ser, *usr).then([this] (auth::role_set roles) {
                return find_service_level(roles);
            }).then([usr, this, func = std::move(func)] (sstring service_level_name) mutable {
                return with_service_level(service_level_name, std::move(func));
            });
        } else {
            return with_service_level(default_service_level_name, std::move(func));
        }
    }

    /**
     * Chack the distributed data for changes in a constant interval and updates
     * the service_levels configuration in accordance (adds, removes, or updates
     * service levels as necessairy).
     * @param interval - the interval is seconds to check the distributed data.
     * @return a future that is resolved when the update loop stops.
     */
    void update_from_distributed_data(std::chrono::duration<float> interval);

    /**
     * Updates the service level data from the distributed data store.
     * @return a future that is resolved when the update is done
     */
    future<> update_service_levels_from_distributed_data();

    future<> add_distributed_service_level(sstring name, service_level_options slo, bool if_not_exsists);
    future<> alter_distributed_service_level(sstring name, service_level_options slo);
    future<> drop_distributed_service_level(sstring name, bool if_exists);
    future<service_levels_info> get_distributed_service_levels();
    future<service_levels_info> get_distributed_service_level(sstring service_level_name);

    /**
     * Returns the service level **in effect** for a user having the given
     * collection of roles.
     * @param roles - the collection of roles to consider
     * @return the name of the service level in effect.
     */
    future<sstring> find_service_level(auth::role_set roles);

private:
    /**
     *  Adds a service level configuration if it doesn't exists, and updates
     *  an the existing one if it does exist.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param slo - the service level configuration
     * @param is_static - is this configuration static or not
     */
    future<> do_add_service_level(sstring name, service_level_options slo, bool is_static = false);

    /**
     *  Removes a service level configuration if it exists.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param remove_static - indicates if it is a removal of a static configuration
     * or not.
     */
    future<> do_remove_service_level(sstring name, bool remove_static);

    /**
     * The notify functions are used by the global service level controller
     * to propagate configuration changes to the local controllers.
     * the returned future is resolved when the local controller is done acting
     * on the notification. updates are done in sequence so their meaning will not
     * change due to execution reordering.
     */
    future<> notify_service_level_added(sstring name, service_level sl_data);
    future<> notify_service_level_updated(sstring name, service_level_options slo);
    future<> notify_service_level_removed(sstring name);

    /**
     * Gets the service level data by name.
     * @param service_level_name - the name of the requested service level
     * @return the service level data if it exists (in the local controller) or
     * get_service_level("default") otherwise.
     */
    service_level& get_service_level(sstring service_level_name) {
        auto sl_it = _service_levels_db.find(service_level_name);
        if (sl_it == _service_levels_db.end() || sl_it->second.marked_for_deletion) {
            sl_it = _service_levels_db.find(default_service_level_name);
        }
        return sl_it->second;
    }

    enum class  set_service_level_op_type {
        add_if_not_exists,
        add,
        alter
    };

    future<> set_distributed_service_level(sstring name, service_level_options slo, set_service_level_op_type op_type);

public:
    static sstring default_service_level_name;
};
}
<commit_msg>qos: make getting service level public<commit_after>/*
 * Copyright (C) 2020 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "seastarx.hh"
#include "log.hh"
#include "auth/role_manager.hh"
#include "auth/authenticated_user.hh"
#include <seastar/core/sstring.hh>
#include <seastar/core/distributed.hh>
#include "auth/service.hh"
#include "service/storage_service.hh"
#include <map>
#include <unordered_set>
#include "qos_common.hh"

namespace db {
    class system_distributed_keyspace;
}
namespace qos {
/**
 *  a structure to hold a service level
 *  data and configuration.
 */
struct service_level {
     service_level_options slo;
     bool marked_for_deletion;
     bool is_static;
};

/**
 *  The service_level_controller class is an implementation of the service level
 *  controller design.
 *  It is logically divided into 2 parts:
 *      1. Global controller which is responsible for all of the data and plumbing
 *      manipulation.
 *      2. Local controllers that act upon the data and facilitates execution in
 *      the service level context
 */
class service_level_controller : public peering_sharded_service<service_level_controller> {
public:
    class service_level_distributed_data_accessor {
    public:
        virtual future<qos::service_levels_info> get_service_levels() const = 0;
        virtual future<qos::service_levels_info> get_service_level(sstring service_level_name) const = 0;
        virtual future<> set_service_level(sstring service_level_name, qos::service_level_options slo) const = 0;
        virtual future<> drop_service_level(sstring service_level_name) const = 0;
    };
    using service_level_distributed_data_accessor_ptr = ::shared_ptr<service_level_distributed_data_accessor>;
private:
    struct global_controller_data {
        service_levels_info  static_configurations{};
        int schedg_group_cnt = 0;
        int io_priority_cnt = 0;
        service_level_options default_service_level_config;
        // The below future is used to serialize work so no reordering can occur.
        // This is needed so for example: delete(x), add(x) will not reverse yielding
        // a completely different result than the one intended.
        future<> work_future = make_ready_future();
        semaphore notifications_serializer = semaphore(1);
        future<> distributed_data_update = make_ready_future();
        abort_source dist_data_update_aborter;
    };

    std::unique_ptr<global_controller_data> _global_controller_db;

    static constexpr shard_id global_controller = 0;

    std::map<sstring, service_level> _service_levels_db;
    std::unordered_map<sstring, sstring> _role_to_service_level;
    service_level _default_service_level;
    service_level_distributed_data_accessor_ptr _sl_data_accessor;
    sharded<auth::service>& _auth_service;
public:
    service_level_controller(sharded<auth::service>& auth_service, service_level_options default_service_level_config);

    /**
     * this function must be called *once* from any shard before any other functions are called.
     * No other function should be called before the future returned by the function is resolved.
     * @return a future that resolves when the initialization is over.
     */
    future<> start();

    void set_distributed_data_accessor(service_level_distributed_data_accessor_ptr sl_data_accessor);

    /**
     *  Adds a service level configuration if it doesn't exists, and updates
     *  an the existing one if it does exist.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param slo - the service level configuration
     * @param is_static - is this configuration static or not
     */
    future<> add_service_level(sstring name, service_level_options slo, bool is_static = false);

    /**
     *  Removes a service level configuration if it exists.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param remove_static - indicates if it is a removal of a static configuration
     * or not.
     */
    future<> remove_service_level(sstring name, bool remove_static);

    /**
     * stops the distributed updater
     * @return a future that is resolved when the updates stopped
     */
    future<> drain();

    /**
     * stops all ongoing operations if exists
     * @return a future that is resolved when all operations has stopped
     */
    future<> stop();

    /**
     * this is an executor of a function with arguments under a service level
     * that corresponds to a given user.
     * @param usr - the user for determining the service level
     * @param func - the function to be executed
     * @return a future that is resolved when the function's operation is resolved
     * (if it returns a future). or a ready future containing the returned value
     * from the function/
     */
    template <typename Ret>
    futurize_t<Ret> with_user_service_level(shared_ptr<auth::authenticated_user> usr, noncopyable_function<Ret()> func) {
        if (usr) {
            auth::service& ser = _auth_service.local();
            return auth::get_roles(ser, *usr).then([this] (auth::role_set roles) {
                return find_service_level(roles);
            }).then([usr, this, func = std::move(func)] (sstring service_level_name) mutable {
                return with_service_level(service_level_name, std::move(func));
            });
        } else {
            return with_service_level(default_service_level_name, std::move(func));
        }
    }

    /**
     * Chack the distributed data for changes in a constant interval and updates
     * the service_levels configuration in accordance (adds, removes, or updates
     * service levels as necessairy).
     * @param interval - the interval is seconds to check the distributed data.
     * @return a future that is resolved when the update loop stops.
     */
    void update_from_distributed_data(std::chrono::duration<float> interval);

    /**
     * Updates the service level data from the distributed data store.
     * @return a future that is resolved when the update is done
     */
    future<> update_service_levels_from_distributed_data();

    future<> add_distributed_service_level(sstring name, service_level_options slo, bool if_not_exsists);
    future<> alter_distributed_service_level(sstring name, service_level_options slo);
    future<> drop_distributed_service_level(sstring name, bool if_exists);
    future<service_levels_info> get_distributed_service_levels();
    future<service_levels_info> get_distributed_service_level(sstring service_level_name);

    /**
     * Returns the service level **in effect** for a user having the given
     * collection of roles.
     * @param roles - the collection of roles to consider
     * @return the name of the service level in effect.
     */
    future<sstring> find_service_level(auth::role_set roles);

    /**
     * Gets the service level data by name.
     * @param service_level_name - the name of the requested service level
     * @return the service level data if it exists (in the local controller) or
     * get_service_level("default") otherwise.
     */
    service_level& get_service_level(sstring service_level_name) {
        auto sl_it = _service_levels_db.find(service_level_name);
        if (sl_it == _service_levels_db.end() || sl_it->second.marked_for_deletion) {
            sl_it = _service_levels_db.find(default_service_level_name);
        }
        return sl_it->second;
    }

private:
    /**
     *  Adds a service level configuration if it doesn't exists, and updates
     *  an the existing one if it does exist.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param slo - the service level configuration
     * @param is_static - is this configuration static or not
     */
    future<> do_add_service_level(sstring name, service_level_options slo, bool is_static = false);

    /**
     *  Removes a service level configuration if it exists.
     *  Handles both, static and non static service level configurations.
     * @param name - the service level name.
     * @param remove_static - indicates if it is a removal of a static configuration
     * or not.
     */
    future<> do_remove_service_level(sstring name, bool remove_static);

    /**
     * The notify functions are used by the global service level controller
     * to propagate configuration changes to the local controllers.
     * the returned future is resolved when the local controller is done acting
     * on the notification. updates are done in sequence so their meaning will not
     * change due to execution reordering.
     */
    future<> notify_service_level_added(sstring name, service_level sl_data);
    future<> notify_service_level_updated(sstring name, service_level_options slo);
    future<> notify_service_level_removed(sstring name);

    enum class  set_service_level_op_type {
        add_if_not_exists,
        add,
        alter
    };

    future<> set_distributed_service_level(sstring name, service_level_options slo, set_service_level_op_type op_type);

public:
    static sstring default_service_level_name;
};
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkObject.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkObject.h"
#include "itkObjectFactory.h"
#include "itkCommand.h"

namespace itk
{
class Observer
{
public:
  Observer(Command* c,
           unsigned long event,
           unsigned long tag) :m_Command(c),
                               m_Event(event),
                               m_Tag(tag)
    { }
  Command::Pointer m_Command;
  unsigned long m_Event;
  unsigned long m_Tag;
};

class SubjectImplementation
{
public:
  SubjectImplementation() {m_Count = 0;}
  ~SubjectImplementation();
  unsigned long AddObserver(unsigned long event, Command* cmd);
  void RemoveObserver(unsigned long tag);
  void InvokeEvent(unsigned long event, Object* self);
  void InvokeEvent(unsigned long event, const Object* self);
  Command *GetCommand(unsigned long tag);
  bool HasObserver(unsigned long event) const;
private:
  std::list<Observer* > m_Observers;
  unsigned long m_Count;
};

SubjectImplementation::
~SubjectImplementation()
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    delete (*i);
    }
}

unsigned long
SubjectImplementation::
AddObserver(unsigned long event,
	    Command* cmd)
{
  Observer* ptr = new Observer(cmd, event, m_Count);
  m_Observers.push_back(ptr);
  m_Count++;
  return ptr->m_Tag;
}

void
SubjectImplementation::
RemoveObserver(unsigned long tag)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    if((*i)->m_Tag == tag)
      {
      delete (*i);
      m_Observers.erase(i);
      return;
      }
    }
}

void
SubjectImplementation::
InvokeEvent(unsigned long event,
	    Object* self)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    unsigned long e =  (*i)->m_Event;
    if( e == Command::AnyEvent || e == event)
      {
      (*i)->m_Command->Execute(self, event);
      }
    }
}

void
SubjectImplementation::
InvokeEvent(unsigned long event,
	    const Object* self)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    unsigned long e =  (*i)->m_Event;
    if( e == Command::AnyEvent || e == event)
      {
      (*i)->m_Command->Execute(self, event);
      }
    }
}

Command*
SubjectImplementation::
GetCommand(unsigned long tag)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    if ( (*i)->m_Tag == tag)
      {
      return (*i)->m_Command;
      }
    }
  return 0;
}

bool
SubjectImplementation::
HasObserver(unsigned long event) const
{
  for(std::list<Observer* >::const_iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    unsigned long e =  (*i)->m_Event;
    if( e == Command::AnyEvent || e == event)
      {
      return true;
      }
    }
  return false;
}

/**
 * Instance creation.
 */
Object::Pointer
Object
::New()
{
  Self *ret = ObjectFactory<Self>::Create();
  if(ret)
    {
    return ret;
    }
  return new Self;
}

/**
 * Turn debugging output on.
 */
void
Object
::DebugOn() const
{
  m_Debug = true;
}

/**
 * Turn debugging output off.
 */
void
Object
::DebugOff() const
{
  m_Debug = false;
}

/**
 * Get the value of the debug flag.
 */
bool
Object
::GetDebug() const
{
  return m_Debug;
}

/**
 * Set the value of the debug flag. A non-zero value turns debugging on.
 */
void
Object
::SetDebug(bool debugFlag) const
{
  m_Debug = debugFlag;
}

/**
 * Return the modification for this object.
 */
unsigned long
Object
::GetMTime() const
{
  return m_MTime.GetMTime();
}

/**
 * Make sure this object's modified time is greater than all others.
 */
void
Object
::Modified() const
{
  m_MTime.Modified();
  InvokeEvent( Command::ModifiedEvent );
}

/**
 * Increase the reference count (mark as used by another object).
 */
void
Object
::Register() const
{
  itkDebugMacro(<< "Registered, "
                << "ReferenceCount = " << (m_ReferenceCount+1));

  // call the parent
  Superclass::Register();
}

/**
 * Decrease the reference count (release by another object).
 */
void
Object
::UnRegister() const
{
  // call the parent
  itkDebugMacro(<< "UnRegistered, "
                << "ReferenceCount = " << (m_ReferenceCount-1));

  if ( (m_ReferenceCount-1) <= 0)
    {
    /**
     * If there is a delete method, invoke it.
     */
    this->InvokeEvent(Command::DeleteEvent);
    }

  Superclass::UnRegister();
}

/**
 * Sets the reference count (use with care)
 */
void
Object
::SetReferenceCount(int ref)
{
  itkDebugMacro(<< "Reference Count set to " << ref);

  // ReferenceCount in now unlocked.  We may have a race condition to
  // to delete the object.
  if( ref <= 0 )
    {
    /**
     * If there is a delete method, invoke it.
     */
    this->InvokeEvent(Command::DeleteEvent);
    }

  Superclass::SetReferenceCount(ref);
}

/**
 * Set the value of the global debug output control flag.
 */
void
Object
::SetGlobalWarningDisplay(bool val)
{
  m_GlobalWarningDisplay = val;
}

/**
 * Get the value of the global debug output control flag.
 */
bool
Object
::GetGlobalWarningDisplay()
{
  return m_GlobalWarningDisplay;
}

unsigned long
Object
::AddObserver(unsigned long event, Command *cmd)
{
  if (!this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation = new SubjectImplementation;
    }
  return this->m_SubjectImplementation->AddObserver(event,cmd);
}

unsigned long
Object
::AddObserver(const char *event,Command *cmd)
{
  return this->AddObserver(Command::GetEventIdFromString(event), cmd);
}

Command*
Object
::GetCommand(unsigned long tag)
{
  if (this->m_SubjectImplementation)
    {
    return this->m_SubjectImplementation->GetCommand(tag);
    }
  return NULL;
}

void
Object
::RemoveObserver(unsigned long tag)
{
  if (this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation->RemoveObserver(tag);
    }
}

void
Object
::InvokeEvent(unsigned long event)
{
  if (this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation->InvokeEvent(event,this);
    }
}

void
Object
::InvokeEvent(unsigned long event) const
{
  if (this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation->InvokeEvent(event,this);
    }
}

void
Object
::InvokeEvent(const char *event)
{
  this->InvokeEvent(Command::GetEventIdFromString(event));
}

void
Object
::InvokeEvent(const char *event) const
{
  this->InvokeEvent(Command::GetEventIdFromString(event));
}

bool
Object
::HasObserver(unsigned long event) const
{
  if (this->m_SubjectImplementation)
    {
    return this->m_SubjectImplementation->HasObserver(event);
    }
  return false;
}

bool
Object
::HasObserver(const char *event) const
{
  return this->HasObserver(Command::GetEventIdFromString(event));
}

/**
 * Create an object with Debug turned off and modified time initialized
 * to the most recently modified object.
 */
Object
::Object():
  LightObject(),
  m_Debug(false),
  m_SubjectImplementation(0)
{
  this->Modified();
}

Object
::~Object()
{
  itkDebugMacro(<< "Destructing!");
  delete m_SubjectImplementation;
}

/**
 * Chaining method to print an object's instance variables, as well as
 * its superclasses.
 */
void
Object
::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Modified Time: " << this->GetMTime() << std::endl;
  os << indent << "Debug: " << (m_Debug ? "On\n" : "Off\n");
  os << indent << "Instance has ";
  if ( this->HasObserver(Command::AnyEvent) )
    {
    os << "one or more observers\n";
    }
  else
    {
    os << "no observers\n";
    }
}

/**
 * Initialize static member that controls warning display.
 */
bool Object::m_GlobalWarningDisplay = true;

} // end namespace itk
<commit_msg>ENH: Events are now itk::EventObject instead of enums.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkObject.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkObject.h"
#include "itkObjectFactory.h"
#include "itkCommand.h"

namespace itk
{
class Observer
{
public:
  Observer(Command* c,
           const EventObject * event,
           unsigned long tag) :m_Command(c),
                               m_Event(event),
                               m_Tag(tag)
    { }
  virtual ~Observer()
  { delete m_Event; }
  Command::Pointer m_Command;
  const EventObject * m_Event;
  unsigned long m_Tag;
};

class SubjectImplementation
{
public:
  SubjectImplementation() {m_Count = 0;}
  ~SubjectImplementation();
  unsigned long AddObserver(const EventObject & event, Command* cmd);
  void RemoveObserver(unsigned long tag);
  void InvokeEvent( const EventObject & event, Object* self);
  void InvokeEvent( const EventObject & event, const Object* self);
  Command *GetCommand(unsigned long tag);
  bool HasObserver(const EventObject & event) const;
private:
  std::list<Observer* > m_Observers;
  unsigned long m_Count;
};

SubjectImplementation::
~SubjectImplementation()
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    delete (*i);
    }
}

unsigned long
SubjectImplementation::
AddObserver(const EventObject & event,
	    Command* cmd)
{
  Observer* ptr = new Observer(cmd, event.New(), m_Count);
  m_Observers.push_back(ptr);
  m_Count++;
  return ptr->m_Tag;
}

void
SubjectImplementation::
RemoveObserver(unsigned long tag)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    if((*i)->m_Tag == tag)
      {
      delete (*i);
      m_Observers.erase(i);
      return;
      }
    }
}

void
SubjectImplementation::
InvokeEvent( const EventObject & event,
	    Object* self)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    const EventObject * e =  (*i)->m_Event;
    if(  typeid( *e ) == typeid( AnyEvent ) ||
         typeid( *e ) == typeid(   event  )    )
      {
      (*i)->m_Command->Execute(self, event);
      }
    }
}

void
SubjectImplementation::
InvokeEvent( const EventObject & event,
	    const Object* self)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    const EventObject * e =  (*i)->m_Event;
    if( typeid( *e ) == typeid( AnyEvent ) ||
        typeid( *e ) == typeid(   event  )     )
      {
      (*i)->m_Command->Execute(self, event);
      }
    }
}

Command*
SubjectImplementation::
GetCommand(unsigned long tag)
{
  for(std::list<Observer* >::iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    if ( (*i)->m_Tag == tag)
      {
      return (*i)->m_Command;
      }
    }
  return 0;
}

bool
SubjectImplementation::
HasObserver(const EventObject & event) const
{
  for(std::list<Observer* >::const_iterator i = m_Observers.begin();
      i != m_Observers.end(); ++i)
    {
    const EventObject * e =  (*i)->m_Event;
    if( typeid( *e ) == typeid( AnyEvent ) ||
        typeid( *e ) == typeid(   event  )     )
      {
      return true;
      }
    }
  return false;
}

/**
 * Instance creation.
 */
Object::Pointer
Object
::New()
{
  Self *ret = ObjectFactory<Self>::Create();
  if(ret)
    {
    return ret;
    }
  return new Self;
}

/**
 * Turn debugging output on.
 */
void
Object
::DebugOn() const
{
  m_Debug = true;
}

/**
 * Turn debugging output off.
 */
void
Object
::DebugOff() const
{
  m_Debug = false;
}

/**
 * Get the value of the debug flag.
 */
bool
Object
::GetDebug() const
{
  return m_Debug;
}

/**
 * Set the value of the debug flag. A non-zero value turns debugging on.
 */
void
Object
::SetDebug(bool debugFlag) const
{
  m_Debug = debugFlag;
}

/**
 * Return the modification for this object.
 */
unsigned long
Object
::GetMTime() const
{
  return m_MTime.GetMTime();
}

/**
 * Make sure this object's modified time is greater than all others.
 */
void
Object
::Modified() const
{
  m_MTime.Modified();
  InvokeEvent( ModifiedEvent() );
}

/**
 * Increase the reference count (mark as used by another object).
 */
void
Object
::Register() const
{
  itkDebugMacro(<< "Registered, "
                << "ReferenceCount = " << (m_ReferenceCount+1));

  // call the parent
  Superclass::Register();
}

/**
 * Decrease the reference count (release by another object).
 */
void
Object
::UnRegister() const
{
  // call the parent
  itkDebugMacro(<< "UnRegistered, "
                << "ReferenceCount = " << (m_ReferenceCount-1));

  if ( (m_ReferenceCount-1) <= 0)
    {
    /**
     * If there is a delete method, invoke it.
     */
    this->InvokeEvent(DeleteEvent());
    }

  Superclass::UnRegister();
}

/**
 * Sets the reference count (use with care)
 */
void
Object
::SetReferenceCount(int ref)
{
  itkDebugMacro(<< "Reference Count set to " << ref);

  // ReferenceCount in now unlocked.  We may have a race condition to
  // to delete the object.
  if( ref <= 0 )
    {
    /**
     * If there is a delete method, invoke it.
     */
    this->InvokeEvent(DeleteEvent());
    }

  Superclass::SetReferenceCount(ref);
}

/**
 * Set the value of the global debug output control flag.
 */
void
Object
::SetGlobalWarningDisplay(bool val)
{
  m_GlobalWarningDisplay = val;
}

/**
 * Get the value of the global debug output control flag.
 */
bool
Object
::GetGlobalWarningDisplay()
{
  return m_GlobalWarningDisplay;
}

unsigned long
Object
::AddObserver(const EventObject & event, Command *cmd)
{
  if (!this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation = new SubjectImplementation;
    }
  return this->m_SubjectImplementation->AddObserver(event,cmd);
}

unsigned long
Object
::AddObserver(const char *eventname,Command *cmd)
{
  const EventObject * event =
         EventObject::CreateEventFromString( eventname );
  return this->AddObserver(*event, cmd);
  delete event;
}

Command*
Object
::GetCommand(unsigned long tag)
{
  if (this->m_SubjectImplementation)
    {
    return this->m_SubjectImplementation->GetCommand(tag);
    }
  return NULL;
}

void
Object
::RemoveObserver(unsigned long tag)
{
  if (this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation->RemoveObserver(tag);
    }
}

void
Object
::InvokeEvent( const EventObject & event )
{
  if (this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation->InvokeEvent(event,this);
    }
}

void
Object
::InvokeEvent( const EventObject & event ) const
{
  if (this->m_SubjectImplementation)
    {
    this->m_SubjectImplementation->InvokeEvent(event,this);
    }
}

void
Object
::InvokeEvent(const char *eventname )
{
  const EventObject * event =
            EventObject::CreateEventFromString( eventname );
  this->InvokeEvent( *event );
  delete event;
}

void
Object
::InvokeEvent(const char *eventname) const
{
  const EventObject * event =
            EventObject::CreateEventFromString( eventname );
  this->InvokeEvent( *event );
  delete event;
}

bool
Object
::HasObserver( const EventObject & event ) const
{
  if (this->m_SubjectImplementation)
    {
    return this->m_SubjectImplementation->HasObserver(event);
    }
  return false;
}

bool
Object
::HasObserver( const char *eventname ) const
{
  const EventObject * event =
            EventObject::CreateEventFromString( eventname );

  const bool result = this->HasObserver( *event );

  delete event;
}

/**
 * Create an object with Debug turned off and modified time initialized
 * to the most recently modified object.
 */
Object
::Object():
  LightObject(),
  m_Debug(false),
  m_SubjectImplementation(0)
{
  this->Modified();
}

Object
::~Object()
{
  itkDebugMacro(<< "Destructing!");
  delete m_SubjectImplementation;
}

/**
 * Chaining method to print an object's instance variables, as well as
 * its superclasses.
 */
void
Object
::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Modified Time: " << this->GetMTime() << std::endl;
  os << indent << "Debug: " << (m_Debug ? "On\n" : "Off\n");
  os << indent << "Instance has ";
  if ( this->HasObserver( AnyEvent() ) )
    {
    os << "one or more observers\n";
    }
  else
    {
    os << "no observers\n";
    }
}

/**
 * Initialize static member that controls warning display.
 */
bool Object::m_GlobalWarningDisplay = true;

} // end namespace itk
<|endoftext|>


<commit_before>#include "config.hpp"
#include <cstdlib>
#include <sstream>
#include <fstream>
#include <libevdev/libevdev.h>
#include <linux/input.h>

#include <compositor.h>

std::ofstream out;

using std::string;
/* TODO: add checks to see if values are correct */

string wayfire_config_section::get_string(string name, string default_value)
{
    auto it = options.find(name);
    return (it == options.end() ? default_value : it->second);
}

int wayfire_config_section::get_int(string name, int df)
{
    auto it = options.find(name);
    return (it == options.end() ? df : std::atoi(it->second.c_str()));
}

int wayfire_config_section::get_duration(string name, int df)
{
    int result = get_int(name, df * (1000 / refresh_rate));
    return result / (1000 / refresh_rate);
}

double wayfire_config_section::get_double(string name, double df)
{
    auto it = options.find(name);
    return (it == options.end() ? df : std::atof(it->second.c_str()));
}

wayfire_key wayfire_config_section::get_key(string name, wayfire_key df)
{
    auto it = options.find(name);
    if (it == options.end())
        return df;

    if (it->second == "none")
        return {0, 0};

    std::stringstream ss(it->second);
    std::vector<std::string> items;
    std::string t;
    while(ss >> t)
        items.push_back(t);

    wayfire_key ans;

    ans.mod = 0;
    for (size_t i = 0; i < items.size() - 1; i++) {
        if (items[i] == "<alt>")
            ans.mod |= MODIFIER_ALT;
        if (items[i] == "<ctrl>")
            ans.mod |= MODIFIER_CTRL;
        if (items[i] == "<shift>")
            ans.mod |= MODIFIER_SHIFT;
        if (items[i] == "<super>")
            ans.mod |= MODIFIER_SUPER;
    }

    ans.keyval = libevdev_event_code_from_name(EV_KEY, items[items.size() - 1].c_str());
    return ans;
}

wayfire_button wayfire_config_section::get_button(string name, wayfire_button df)
{
    auto it = options.find(name);
    if (it == options.end())
        return df;

    if (it->second == "none")
        return {0, 0};

    std::stringstream ss(it->second);
    std::vector<std::string> items;
    std::string t;
    while(ss >> t)
        items.push_back(t);

    wayfire_button ans;

    ans.mod = 0;
    for (size_t i = 0; i < items.size() - 1; i++) {
        if (items[i] == "<alt>")
            ans.mod |= MODIFIER_ALT;
        if (items[i] == "<ctrl>")
            ans.mod |= MODIFIER_CTRL;
        if (items[i] == "<shift>")
            ans.mod |= MODIFIER_SHIFT;
        if (items[i] == "<super>")
            ans.mod |= MODIFIER_SUPER;
    }

    auto button = items[items.size() - 1];
    if (button == "left")
        ans.button = BTN_LEFT;
    else if (button == "right")
        ans.button = BTN_RIGHT;
    else if (button == "middle")
        ans.button = BTN_MIDDLE;
    else
        ans.button = 0;

    return ans;
}

wayfire_color wayfire_config_section::get_color(string name, wayfire_color df)
{
    auto it = options.find(name);
    if (it == options.end())
        return df;

    wayfire_color ans = {0, 0, 0, 0};
    std::stringstream ss(it->second);
    ss >> ans.r >> ans.g >> ans.b >> ans.a;
    return ans;
}

namespace {
    string trim(string x)
    {
        int i = 0, j = x.length() - 1;
        while(i < (int)x.length() && x[i] == ' ') ++i;
        while(j >= 0 && x[j] == ' ') --j;

        if (i <= j)
            return x.substr(i, j - i + 1);
        else
            return "";
    }
}

wayfire_config::wayfire_config(string name, int rr)
{
    std::ifstream file(name);
    string line;
	out.open("/tmp/out");
out << "use config: " << name << std::endl;

    refresh_rate = rr;
    wayfire_config_section *current_section;
    int line_id = -1;

    while(std::getline(file, line)) {
        ++line_id;
        if (line.size() == 0 || line[0] == '#')
            continue;
out << "process line " << line << std::endl;

        if (line[0] == '[') {
            current_section = new wayfire_config_section();
            current_section->refresh_rate = rr;
            current_section->name = line.substr(1, line.size() - 2);
            sections.push_back(current_section);
            continue;
        }

        string name, value;
        int i = 0;
        while (i < (int)line.size() && line[i] != '=') i++;
	name = trim(line.substr(0, i));
	if (i < (int)line.size()) {
		value = trim(line.substr(i + 1, line.size() - i - 1));
		current_section->options[name] = value;
	}
    }
}

wayfire_config_section* wayfire_config::get_section(string name)
{
    for (auto section : sections)
        if (section->name == name)
            return section;

    auto nsect = new wayfire_config_section();
    nsect->name = name;
    nsect->refresh_rate = refresh_rate;
    sections.push_back(nsect);
    return nsect;
}
<commit_msg>config: trim each line from config before processing it<commit_after>#include "config.hpp"
#include <cstdlib>
#include <sstream>
#include <fstream>
#include <libevdev/libevdev.h>
#include <linux/input.h>

#include <compositor.h>

#include <config.h>

std::ofstream out;

using std::string;
/* TODO: add checks to see if values are correct */

string wayfire_config_section::get_string(string name, string default_value)
{
    auto it = options.find(name);
    return (it == options.end() ? default_value : it->second);
}

int wayfire_config_section::get_int(string name, int df)
{
    auto it = options.find(name);
    return (it == options.end() ? df : std::atoi(it->second.c_str()));
}

int wayfire_config_section::get_duration(string name, int df)
{
    int result = get_int(name, df * (1000 / refresh_rate));
    return result / (1000 / refresh_rate);
}

double wayfire_config_section::get_double(string name, double df)
{
    auto it = options.find(name);
    return (it == options.end() ? df : std::atof(it->second.c_str()));
}

wayfire_key wayfire_config_section::get_key(string name, wayfire_key df)
{
    auto it = options.find(name);
    if (it == options.end())
        return df;

    if (it->second == "none")
        return {0, 0};

    std::stringstream ss(it->second);
    std::vector<std::string> items;
    std::string t;
    while(ss >> t)
        items.push_back(t);

    wayfire_key ans;

    ans.mod = 0;
    for (size_t i = 0; i < items.size() - 1; i++) {
        if (items[i] == "<alt>")
            ans.mod |= MODIFIER_ALT;
        if (items[i] == "<ctrl>")
            ans.mod |= MODIFIER_CTRL;
        if (items[i] == "<shift>")
            ans.mod |= MODIFIER_SHIFT;
        if (items[i] == "<super>")
            ans.mod |= MODIFIER_SUPER;
    }

    ans.keyval = libevdev_event_code_from_name(EV_KEY, items[items.size() - 1].c_str());
    return ans;
}

wayfire_button wayfire_config_section::get_button(string name, wayfire_button df)
{
    auto it = options.find(name);
    if (it == options.end())
        return df;

    if (it->second == "none")
        return {0, 0};

    std::stringstream ss(it->second);
    std::vector<std::string> items;
    std::string t;
    while(ss >> t)
        items.push_back(t);

    if (items.empty())
        return df;

    wayfire_button ans;
    ans.mod = 0;

    for (size_t i = 0; i < items.size() - 1; i++)
    {
        if (items[i] == "<alt>")
            ans.mod |= MODIFIER_ALT;
        if (items[i] == "<ctrl>")
            ans.mod |= MODIFIER_CTRL;
        if (items[i] == "<shift>")
            ans.mod |= MODIFIER_SHIFT;
        if (items[i] == "<super>")
            ans.mod |= MODIFIER_SUPER;
    }

    auto button = items[items.size() - 1];
    if (button == "left")
        ans.button = BTN_LEFT;
    else if (button == "right")
        ans.button = BTN_RIGHT;
    else if (button == "middle")
        ans.button = BTN_MIDDLE;
    else
        ans.button = 0;

    return ans;
}

wayfire_color wayfire_config_section::get_color(string name, wayfire_color df)
{
    auto it = options.find(name);
    if (it == options.end())
        return df;

    wayfire_color ans = {0, 0, 0, 0};
    std::stringstream ss(it->second);
    ss >> ans.r >> ans.g >> ans.b >> ans.a;
    return ans;
}

namespace
{
    string trim(string x)
    {
        int i = 0, j = x.length() - 1;
        while(i < (int)x.length() && std::iswspace(x[i])) ++i;
        while(j >= 0 && std::iswspace(x[j])) --j;

        if (i <= j)
            return x.substr(i, j - i + 1);
        else
            return "";
    }
}

wayfire_config::wayfire_config(string name, int rr)
{
    std::ifstream file(name);
    string line;

#if WAYFIRE_DEBUG_ENABLED
    out.open("/tmp/.wayfire_config_debug");
    out << "use config: " << name << std::endl;
#endif

    refresh_rate = rr;
    wayfire_config_section *current_section;
    int line_id = -1;

    while(std::getline(file, line))
    {
        ++line_id;

        line = trim(line);
        if (line.size() == 0 || line[0] == '#')
            continue;

#if WAYFIRE_DEBUG_ENABLED
        out << "process line " << line << std::endl;
#endif

        if (line[0] == '[')
        {
            current_section = new wayfire_config_section();
            current_section->refresh_rate = rr;
            current_section->name = line.substr(1, line.size() - 2);
            sections.push_back(current_section);
            continue;
        }

        string name, value;
        int i = 0;
        while (i < (int)line.size() && line[i] != '=') i++;
        name = trim(line.substr(0, i));
        if (i < (int)line.size())
        {
            value = trim(line.substr(i + 1, line.size() - i - 1));
            current_section->options[name] = value;
        }
    }
}

wayfire_config_section* wayfire_config::get_section(string name)
{
    for (auto section : sections)
        if (section->name == name)
            return section;

    auto nsect = new wayfire_config_section();
    nsect->name = name;
    nsect->refresh_rate = refresh_rate;
    sections.push_back(nsect);
    return nsect;
}
<|endoftext|>


<commit_before>/*
 * NoSelfKernelConn.cpp
 *
 *  Created on: Sep 20, 2011
 *      Author: gkenyon
 */

#include "NoSelfKernelConn.hpp"

namespace PV {

NoSelfKernelConn::NoSelfKernelConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
            ChannelType channel, const char * filename) : KernelConn(name, hc, pre, post,
                  channel, filename){};
NoSelfKernelConn::NoSelfKernelConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
            ChannelType channel, const char * filename, InitWeights *weightInit) : KernelConn(name, hc, pre, post,
                  channel, filename, weightInit){};
NoSelfKernelConn::NoSelfKernelConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
            ChannelType channel) : KernelConn(name, hc, pre, post,
                  channel){};

int NoSelfKernelConn::normalizeWeights(PVPatch ** patches, int numPatches, int arborId)
{
   //int axonID = 0;
   // self-interactions only defined for layers of same size
   assert(this->getPre()->getCLayer()->loc.nx == this->getPost()->getCLayer()->loc.nx);
   assert(this->getPre()->getCLayer()->loc.ny == this->getPost()->getCLayer()->loc.ny);
   assert(this->getPre()->getCLayer()->loc.nf == this->getPost()->getCLayer()->loc.nf);
   int num_kernels = this->numDataPatches();

   for (int kPatch = 0; kPatch < num_kernels; kPatch++) {
      PVPatch * wp = getKernelPatch(arborId, kPatch);
      pvdata_t * w = wp->data;
      int kfSelf = kPatch;
      int kxSelf = (nxp / 2);
      int kySelf = (nyp / 2);
      int kSelf = kIndex(kxSelf, kySelf, kfSelf, nxp, nyp, nfp);
      w[kSelf] = 0.0f;
   }
   return KernelConn::normalizeWeights(patches, numPatches, arborId);
}

} /* namespace PV */
<commit_msg>NoSelfConn now zeros all arbors in first call to normalizeWeights, for consistency with KernelConn::normalizeWeights, which should always return PV_BREAK<commit_after>/*
 * NoSelfKernelConn.cpp
 *
 *  Created on: Sep 20, 2011
 *      Author: gkenyon
 */

#include "NoSelfKernelConn.hpp"

namespace PV {

NoSelfKernelConn::NoSelfKernelConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
            ChannelType channel, const char * filename) : KernelConn(name, hc, pre, post,
                  channel, filename){};
NoSelfKernelConn::NoSelfKernelConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
            ChannelType channel, const char * filename, InitWeights *weightInit) : KernelConn(name, hc, pre, post,
                  channel, filename, weightInit){};
NoSelfKernelConn::NoSelfKernelConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
            ChannelType channel) : KernelConn(name, hc, pre, post,
                  channel){};

int NoSelfKernelConn::normalizeWeights(PVPatch ** patches, int numPatches, int arborId)
{
   //int axonID = 0;
   // self-interactions only defined for layers of same size
   assert(this->getPre()->getCLayer()->loc.nx == this->getPost()->getCLayer()->loc.nx);
   assert(this->getPre()->getCLayer()->loc.ny == this->getPost()->getCLayer()->loc.ny);
   assert(this->getPre()->getCLayer()->loc.nf == this->getPost()->getCLayer()->loc.nf);
   int num_kernels = this->numDataPatches();

   // because the default return value/behavior of KernelConn::normalizeWeights is PV_BREAK,
   // safest approach here is to zero self-interactions for all arbors
   assert(arborId == 0);  // necessary?  could execute this routine numAxonArbors times without apparent harm
   for (int axonIndex = 0; axonIndex < this->numberOfAxonalArborLists(); axonIndex++) {
      for (int kPatch = 0; kPatch < num_kernels; kPatch++) {
         PVPatch * wp = getKernelPatch(axonIndex, kPatch);
         pvdata_t * w = wp->data;
         int kfSelf = kPatch;
         int kxSelf = (nxp / 2);
         int kySelf = (nyp / 2);
         int kSelf = kIndex(kxSelf, kySelf, kfSelf, nxp, nyp, nfp);
         w[kSelf] = 0.0f;
      } // kPatch
   }  // axonIndex
   return KernelConn::normalizeWeights(patches, numPatches, arborId);  // parent class should return PV_BREAK
}

} /* namespace PV */
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkPNGImageIO.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkPNGImageIO.h"
#include "png.h"

namespace itk
{

// simple class to call fopen on construct and
// fclose on destruct
struct PNGFileWrapper
{
  PNGFileWrapper(const char* fname)
    {
      m_FilePointer = fopen(fname, "rb");
    }
  FILE* m_FilePointer;
  ~PNGFileWrapper()
    {
      if(m_FilePointer)
        {
        fclose(m_FilePointer);
        }
    }
};

bool PNGImageIO::CanReadFile(const char* file)
{
  PNGFileWrapper pngfp(file);
  FILE* fp = pngfp.m_FilePointer;
  if(!fp)
    {
    return false;
    }
  unsigned char header[8];
  fread(header, 1, 8, fp);
  bool is_png = !png_sig_cmp(header, 0, 8);
  if(!is_png)
    {
    return false;
    }
  png_structp png_ptr = png_create_read_struct
    (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
     NULL, NULL);
  if (!png_ptr)
    {
    return false;
    }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
    png_destroy_read_struct(&png_ptr,
                            (png_infopp)NULL, (png_infopp)NULL);
    return false;
    }

  png_infop end_info = png_create_info_struct(png_ptr);
  if (!end_info)
    {
    png_destroy_read_struct(&png_ptr, &info_ptr,
                            (png_infopp)NULL);
    return false;
    }
  png_destroy_read_struct(&png_ptr, &info_ptr,
                          (png_infopp)NULL);

  return true;
}

const std::type_info& PNGImageIO::GetPixelType() const
{
  switch(m_PNGPixelType)
    {
    case UCHAR:
      return typeid(unsigned char);
    case USHORT:
      return typeid(unsigned short);
    case CHAR:
    case SHORT:
    case UINT:
    case INT:
    case ULONG:
    case LONG:
    case FLOAT:
    case DOUBLE:
      {
      itkErrorMacro ("Invalid type: " << m_PNGPixelType << ", only unsigned char and unsigned short are allowed.");
      return this->ConvertToTypeInfo(m_PNGPixelType);
      }
    default:
      return typeid(unsigned char);
    }
}

unsigned int PNGImageIO::GetComponentSize() const
{
  switch(m_PNGPixelType)
    {
    case UCHAR:
      return sizeof(unsigned char);
    case USHORT:
      return sizeof(unsigned short);
    }
  return 1;
}

void PNGImageIO::Load(void* buffer)
{
  // use this class so return will call close
  PNGFileWrapper pngfp(this->GetFileName());
  FILE* fp = pngfp.m_FilePointer;
  if(!fp)
    {
    itkErrorMacro("Error PNGImageIO could not open file: "
                  << this->GetFileName());
    return;
    }
  unsigned char header[8];
  fread(header, 1, 8, fp);
  bool is_png = !png_sig_cmp(header, 0, 8);
  if(!is_png)
    {
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }
  png_structp png_ptr = png_create_read_struct
    (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
     NULL, NULL);
  if (!png_ptr)
    {
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
    png_destroy_read_struct(&png_ptr,
                            (png_infopp)NULL, (png_infopp)NULL);
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }

  png_infop end_info = png_create_info_struct(png_ptr);
  if (!end_info)
    {
    png_destroy_read_struct(&png_ptr, &info_ptr,
                            (png_infopp)NULL);
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  png_uint_32 width, height;
  int bit_depth, color_type, interlace_type;
  int compression_type, filter_method;
  png_get_IHDR(png_ptr, info_ptr,
               &width, &height,
               &bit_depth, &color_type, &interlace_type,
               &compression_type, &filter_method);

  // convert palettes to RGB
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
    png_set_palette_to_rgb(png_ptr);
    }

  // minimum of a byte per pixel
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    {
    png_set_gray_1_2_4_to_8(png_ptr);
    }

  // add alpha if any alpha found
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
    png_set_tRNS_to_alpha(png_ptr);
    }

  if (bit_depth > 8)
    {
#ifndef ITK_WORDS_BIGENDIAN
    png_set_swap(png_ptr);
#endif
    }

   // have libpng handle interlacing
  //int number_of_passes = png_set_interlace_handling(png_ptr);
  // update the info now that we have defined the filters
  png_read_update_info(png_ptr, info_ptr);

  unsigned long rowbytes = png_get_rowbytes(png_ptr, info_ptr);
  unsigned char *tempImage = static_cast<unsigned char*>(buffer);
  png_bytep *row_pointers = new png_bytep [height];
  for (int ui = 0; ui < height; ++ui)
    {
    row_pointers[ui] = tempImage + rowbytes*ui;
    }
  png_read_image(png_ptr, row_pointers);
  delete [] row_pointers;
  // close the file
  png_read_end(png_ptr, NULL);
  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

  m_Spacing[0] = 1.0;  // Is there any spacing information
  m_Spacing[1] = 1.0;  // in PNG ?

  m_Origin[0] = 0.0;
  m_Origin[1] = 0.0;
}

const double*
PNGImageIO::GetOrigin() const
{
  return m_Origin;
}

const double*
PNGImageIO::GetSpacing() const
{
  return m_Spacing;
}

PNGImageIO::PNGImageIO()
{
  this->SetNumberOfDimensions(2);
  m_PNGPixelType = UCHAR;
}

PNGImageIO::~PNGImageIO()
{
}

void PNGImageIO::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
  os << indent << "PNGPixelType " << m_PNGPixelType << "\n";
}

void PNGImageIO::ReadImageInformation()
{
  // use this class so return will call close
  PNGFileWrapper pngfp(m_FileName.c_str());
  FILE* fp = pngfp.m_FilePointer;
  if(!fp)
    {
    return;
    }
  unsigned char header[8];
  fread(header, 1, 8, fp);
  bool is_png = !png_sig_cmp(header, 0, 8);
  if(!is_png)
    {
    return;
    }
  png_structp png_ptr = png_create_read_struct
    (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
     NULL, NULL);
  if (!png_ptr)
    {
    return;
    }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
    png_destroy_read_struct(&png_ptr,
                            (png_infopp)NULL, (png_infopp)NULL);
    return;
    }

  png_infop end_info = png_create_info_struct(png_ptr);
  if (!end_info)
    {
    png_destroy_read_struct(&png_ptr, &info_ptr,
                            (png_infopp)NULL);
    return;
    }

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  png_uint_32 width, height;
  int bit_depth, color_type, interlace_type;
  int compression_type, filter_method;
  png_get_IHDR(png_ptr, info_ptr,
               &width, &height,
               &bit_depth, &color_type, &interlace_type,
               &compression_type, &filter_method);

  // convert palettes to RGB
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
    png_set_palette_to_rgb(png_ptr);
    }

  // minimum of a byte per pixel
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    {
    png_set_gray_1_2_4_to_8(png_ptr);
    }

  // add alpha if any alpha found
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
    png_set_tRNS_to_alpha(png_ptr);
    }

  // update the info now that we have defined the filters
  png_read_update_info(png_ptr, info_ptr);
  this->SetNumberOfDimensions(2);
  this->m_Dimensions[0] = width;
  this->m_Dimensions[1] = height;
  if (bit_depth <= 8)
    {
    m_PNGPixelType = UCHAR;
    }
  else
    {
    m_PNGPixelType = USHORT;
    }
  this->SetNumberOfComponents(png_get_channels(png_ptr, info_ptr));
  png_destroy_read_struct(&png_ptr, &info_ptr,
                          (png_infopp)NULL);
  return;
}

} // end namespace itk
<commit_msg>ERR: waernings on switch.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkPNGImageIO.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkPNGImageIO.h"
#include "png.h"

namespace itk
{

// simple class to call fopen on construct and
// fclose on destruct
struct PNGFileWrapper
{
  PNGFileWrapper(const char* fname)
    {
      m_FilePointer = fopen(fname, "rb");
    }
  FILE* m_FilePointer;
  ~PNGFileWrapper()
    {
      if(m_FilePointer)
        {
        fclose(m_FilePointer);
        }
    }
};

bool PNGImageIO::CanReadFile(const char* file)
{
  PNGFileWrapper pngfp(file);
  FILE* fp = pngfp.m_FilePointer;
  if(!fp)
    {
    return false;
    }
  unsigned char header[8];
  fread(header, 1, 8, fp);
  bool is_png = !png_sig_cmp(header, 0, 8);
  if(!is_png)
    {
    return false;
    }
  png_structp png_ptr = png_create_read_struct
    (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
     NULL, NULL);
  if (!png_ptr)
    {
    return false;
    }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
    png_destroy_read_struct(&png_ptr,
                            (png_infopp)NULL, (png_infopp)NULL);
    return false;
    }

  png_infop end_info = png_create_info_struct(png_ptr);
  if (!end_info)
    {
    png_destroy_read_struct(&png_ptr, &info_ptr,
                            (png_infopp)NULL);
    return false;
    }
  png_destroy_read_struct(&png_ptr, &info_ptr,
                          (png_infopp)NULL);

  return true;
}

const std::type_info& PNGImageIO::GetPixelType() const
{
  switch(m_PNGPixelType)
    {
    case UCHAR:
      return typeid(unsigned char);
    case USHORT:
      return typeid(unsigned short);
    case CHAR:
    case SHORT:
    case UINT:
    case INT:
    case ULONG:
    case LONG:
    case FLOAT:
    case DOUBLE:
      {
      itkErrorMacro ("Invalid type: " << m_PNGPixelType << ", only unsigned char and unsigned short are allowed.");
      return this->ConvertToTypeInfo(m_PNGPixelType);
      }
    default:
      return typeid(unsigned char);
    }
}

unsigned int PNGImageIO::GetComponentSize() const
{
  switch(m_PNGPixelType)
    {
    case UCHAR:
      return sizeof(unsigned char);
    case USHORT:
      return sizeof(unsigned short);
    case CHAR:
    case SHORT:
    case UINT:
    case INT:
    case ULONG:
    case LONG:
    case FLOAT:
    case DOUBLE:
      {
      itkErrorMacro ("Invalid type: " << m_PNGPixelType << ", only unsigned char and unsigned short are allowed.");
      return 0;
      }
    }
  return 1;
}

void PNGImageIO::Load(void* buffer)
{
  // use this class so return will call close
  PNGFileWrapper pngfp(this->GetFileName());
  FILE* fp = pngfp.m_FilePointer;
  if(!fp)
    {
    itkErrorMacro("Error PNGImageIO could not open file: "
                  << this->GetFileName());
    return;
    }
  unsigned char header[8];
  fread(header, 1, 8, fp);
  bool is_png = !png_sig_cmp(header, 0, 8);
  if(!is_png)
    {
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }
  png_structp png_ptr = png_create_read_struct
    (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
     NULL, NULL);
  if (!png_ptr)
    {
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
    png_destroy_read_struct(&png_ptr,
                            (png_infopp)NULL, (png_infopp)NULL);
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }

  png_infop end_info = png_create_info_struct(png_ptr);
  if (!end_info)
    {
    png_destroy_read_struct(&png_ptr, &info_ptr,
                            (png_infopp)NULL);
    itkErrorMacro("Error File is not png type" << this->GetFileName());
    return;
    }

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  png_uint_32 width, height;
  int bit_depth, color_type, interlace_type;
  int compression_type, filter_method;
  png_get_IHDR(png_ptr, info_ptr,
               &width, &height,
               &bit_depth, &color_type, &interlace_type,
               &compression_type, &filter_method);

  // convert palettes to RGB
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
    png_set_palette_to_rgb(png_ptr);
    }

  // minimum of a byte per pixel
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    {
    png_set_gray_1_2_4_to_8(png_ptr);
    }

  // add alpha if any alpha found
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
    png_set_tRNS_to_alpha(png_ptr);
    }

  if (bit_depth > 8)
    {
#ifndef ITK_WORDS_BIGENDIAN
    png_set_swap(png_ptr);
#endif
    }

   // have libpng handle interlacing
  //int number_of_passes = png_set_interlace_handling(png_ptr);
  // update the info now that we have defined the filters
  png_read_update_info(png_ptr, info_ptr);

  unsigned long rowbytes = png_get_rowbytes(png_ptr, info_ptr);
  unsigned char *tempImage = static_cast<unsigned char*>(buffer);
  png_bytep *row_pointers = new png_bytep [height];
  for (int ui = 0; ui < height; ++ui)
    {
    row_pointers[ui] = tempImage + rowbytes*ui;
    }
  png_read_image(png_ptr, row_pointers);
  delete [] row_pointers;
  // close the file
  png_read_end(png_ptr, NULL);
  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

  m_Spacing[0] = 1.0;  // Is there any spacing information
  m_Spacing[1] = 1.0;  // in PNG ?

  m_Origin[0] = 0.0;
  m_Origin[1] = 0.0;
}

const double*
PNGImageIO::GetOrigin() const
{
  return m_Origin;
}

const double*
PNGImageIO::GetSpacing() const
{
  return m_Spacing;
}

PNGImageIO::PNGImageIO()
{
  this->SetNumberOfDimensions(2);
  m_PNGPixelType = UCHAR;
}

PNGImageIO::~PNGImageIO()
{
}

void PNGImageIO::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
  os << indent << "PNGPixelType " << m_PNGPixelType << "\n";
}

void PNGImageIO::ReadImageInformation()
{
  // use this class so return will call close
  PNGFileWrapper pngfp(m_FileName.c_str());
  FILE* fp = pngfp.m_FilePointer;
  if(!fp)
    {
    return;
    }
  unsigned char header[8];
  fread(header, 1, 8, fp);
  bool is_png = !png_sig_cmp(header, 0, 8);
  if(!is_png)
    {
    return;
    }
  png_structp png_ptr = png_create_read_struct
    (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
     NULL, NULL);
  if (!png_ptr)
    {
    return;
    }

  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
    png_destroy_read_struct(&png_ptr,
                            (png_infopp)NULL, (png_infopp)NULL);
    return;
    }

  png_infop end_info = png_create_info_struct(png_ptr);
  if (!end_info)
    {
    png_destroy_read_struct(&png_ptr, &info_ptr,
                            (png_infopp)NULL);
    return;
    }

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  png_uint_32 width, height;
  int bit_depth, color_type, interlace_type;
  int compression_type, filter_method;
  png_get_IHDR(png_ptr, info_ptr,
               &width, &height,
               &bit_depth, &color_type, &interlace_type,
               &compression_type, &filter_method);

  // convert palettes to RGB
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
    png_set_palette_to_rgb(png_ptr);
    }

  // minimum of a byte per pixel
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    {
    png_set_gray_1_2_4_to_8(png_ptr);
    }

  // add alpha if any alpha found
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
    png_set_tRNS_to_alpha(png_ptr);
    }

  // update the info now that we have defined the filters
  png_read_update_info(png_ptr, info_ptr);
  this->SetNumberOfDimensions(2);
  this->m_Dimensions[0] = width;
  this->m_Dimensions[1] = height;
  if (bit_depth <= 8)
    {
    m_PNGPixelType = UCHAR;
    }
  else
    {
    m_PNGPixelType = USHORT;
    }
  this->SetNumberOfComponents(png_get_channels(png_ptr, info_ptr));
  png_destroy_read_struct(&png_ptr, &info_ptr,
                          (png_infopp)NULL);
  return;
}

} // end namespace itk
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkVTKImageIO.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkVTKImageIO.h"

namespace itk
{

VTKImageIO::VTKImageIO()
{
  this->SetNumberOfDimensions(2);
  m_ByteOrder = LittleEndian;
  m_FileType = ASCII;

}

VTKImageIO::~VTKImageIO()
{
}

bool VTKImageIO::OpenVTKFile(std::ofstream& os, const char* filename,
                             int openMode)
{
  // Make sure that we have a file to
  if ( filename == "" )
    {
    itkErrorMacro(<<"A FileName must be specified.");
    return false;
    }

  // Close file from any previous image
  if ( os.is_open() )
    {
    os.close();
    }

  // Open the new file for reading
  itkDebugMacro(<< "Initialize: opening file " << filename);

  // Actually open the file
#ifdef _WIN32
  openMode |= std::ios::binary;
#endif
  os.open(filename, openMode);
  if ( os.fail() )
    {
    itkErrorMacro(<< "Could not open file: " << filename);
    return false;
    }

  return true;
}

bool VTKImageIO::CanReadFile(const char* filename)
{
  std::ofstream file;
  std::string fname(filename);

  if ( ! this->OpenVTKFile(file,m_FileName.c_str(),std::ios::in) )
    {
    return false;
    }

  // Check to see if its a vtk structured points file
  if ( fname.find(".vtk") < fname.length() )
    {
    }

  return true;
}

void VTKImageIO::Read(void* buffer)
{
  // Read the header, make sure it is

}

void VTKImageIO::ReadImageInformation()
{
}

bool VTKImageIO::CanWriteFile(const char*)
{
  if ( m_FileName != "" &&
       m_FileName.find(".vtk") < m_FileName.length() )
    {
    return true;
    }
  return false;
}

void VTKImageIO::Write(void* buffer)
{
  std::ofstream file;
  if ( ! this->OpenVTKFile(file,m_FileName.c_str(),std::ios::out) )
    {
    return;
    }

  // Check the image region for proper dimensions, etc.
  unsigned int numDims = this->GetNumberOfDimensions();
  if ( numDims < 2 || numDims > 3 )
    {
    itkErrorMacro(<<"VTK Writer can only write 2 or 3-dimensional images");
    return;
    }
  ImageIORegion ioRegion = this->GetIORegion();

  // Write the VTK header information
  file << "# vtk DataFile Version 3.0\n";
  file << "VTK File Generated by Insight Segmentation and Registration Toolkit (ITK)\n";

  if ( this->GetFileType() == ASCII ) { file << "ASCII\n"; }
  else { file << "BINARY\n"; }

  // Write characteristics of the data
  file << "DATASET STRUCTURED_POINTS\n";
  if ( numDims == 2 )
    {
    file << "DIMENSIONS " << this->GetDimensions(0) << " "
           << this->GetDimensions(1) << " 1\n";
    file << "SPACING " << m_Spacing[0] << " " << m_Spacing[1] << " 1.0\n";
    file << "ORIGIN " << m_Origin[0] << " " << m_Origin[1] << " 0.0\n";
    }
  else //numDims == 3
    {
    file << "DIMENSIONS " << this->GetDimensions(0) << " "
           << this->GetDimensions(1) << this->GetDimensions(2) << "\n";
    file << "SPACING " << m_Spacing[0] << " "
           << m_Spacing[1] << " " << m_Spacing[2] << "\n";
    file << "ORIGIN " << m_Origin[0] << " "
           << m_Origin[1] << " " << m_Origin[2] << "\n";
    }

  file << "POINT_DATA " << this->GetImageSizeInPixels() << "\n";
  file << "SCALARS scalars "
         << this->ReturnTypeAsString(this->GetComponentType()) << " "
         << this->GetNumberOfComponents() << "\n";
  file << "LOOKUP_TABLE default\n";

  // Write the actual pixel data
  if ( m_FileType == ASCII )
    {
    this->WriteBufferAsASCII(file, buffer, this->GetComponentType(),
                             this->GetImageSizeInComponents());
    }
  else //binary
    {
    file.write(static_cast<char*>(buffer), this->GetImageSizeInBytes());
    }
}

void VTKImageIO::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
}

} // end namespace itk
<commit_msg>ERR: File open mode needs to be cast to standard conformant std::ios_base::openmode, but not all compilers support this.  The cast is done only for GCC 3.0 and above.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkVTKImageIO.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkVTKImageIO.h"

namespace itk
{

VTKImageIO::VTKImageIO()
{
  this->SetNumberOfDimensions(2);
  m_ByteOrder = LittleEndian;
  m_FileType = ASCII;

}

VTKImageIO::~VTKImageIO()
{
}

bool VTKImageIO::OpenVTKFile(std::ofstream& os, const char* filename,
                             int openMode)
{
  // Make sure that we have a file to
  if ( filename == "" )
    {
    itkErrorMacro(<<"A FileName must be specified.");
    return false;
    }

  // Close file from any previous image
  if ( os.is_open() )
    {
    os.close();
    }

  // Open the new file for reading
  itkDebugMacro(<< "Initialize: opening file " << filename);

  // Actually open the file
#ifdef _WIN32
  openMode |= std::ios::binary;
#endif
#if defined(__GNUC__) && __GNUC__ >= 3
  os.open(filename, static_cast<std::ios_base::openmode>(openMode));
#else
  os.open(filename, openMode);
#endif
  if ( os.fail() )
    {
    itkErrorMacro(<< "Could not open file: " << filename);
    return false;
    }

  return true;
}

bool VTKImageIO::CanReadFile(const char* filename)
{
  std::ofstream file;
  std::string fname(filename);

  if ( ! this->OpenVTKFile(file,m_FileName.c_str(),std::ios::in) )
    {
    return false;
    }

  // Check to see if its a vtk structured points file
  if ( fname.find(".vtk") < fname.length() )
    {
    }

  return true;
}

void VTKImageIO::Read(void* buffer)
{
  // Read the header, make sure it is

}

void VTKImageIO::ReadImageInformation()
{
}

bool VTKImageIO::CanWriteFile(const char*)
{
  if ( m_FileName != "" &&
       m_FileName.find(".vtk") < m_FileName.length() )
    {
    return true;
    }
  return false;
}

void VTKImageIO::Write(void* buffer)
{
  std::ofstream file;
  if ( ! this->OpenVTKFile(file,m_FileName.c_str(),std::ios::out) )
    {
    return;
    }

  // Check the image region for proper dimensions, etc.
  unsigned int numDims = this->GetNumberOfDimensions();
  if ( numDims < 2 || numDims > 3 )
    {
    itkErrorMacro(<<"VTK Writer can only write 2 or 3-dimensional images");
    return;
    }
  ImageIORegion ioRegion = this->GetIORegion();

  // Write the VTK header information
  file << "# vtk DataFile Version 3.0\n";
  file << "VTK File Generated by Insight Segmentation and Registration Toolkit (ITK)\n";

  if ( this->GetFileType() == ASCII ) { file << "ASCII\n"; }
  else { file << "BINARY\n"; }

  // Write characteristics of the data
  file << "DATASET STRUCTURED_POINTS\n";
  if ( numDims == 2 )
    {
    file << "DIMENSIONS " << this->GetDimensions(0) << " "
           << this->GetDimensions(1) << " 1\n";
    file << "SPACING " << m_Spacing[0] << " " << m_Spacing[1] << " 1.0\n";
    file << "ORIGIN " << m_Origin[0] << " " << m_Origin[1] << " 0.0\n";
    }
  else //numDims == 3
    {
    file << "DIMENSIONS " << this->GetDimensions(0) << " "
           << this->GetDimensions(1) << this->GetDimensions(2) << "\n";
    file << "SPACING " << m_Spacing[0] << " "
           << m_Spacing[1] << " " << m_Spacing[2] << "\n";
    file << "ORIGIN " << m_Origin[0] << " "
           << m_Origin[1] << " " << m_Origin[2] << "\n";
    }

  file << "POINT_DATA " << this->GetImageSizeInPixels() << "\n";
  file << "SCALARS scalars "
         << this->ReturnTypeAsString(this->GetComponentType()) << " "
         << this->GetNumberOfComponents() << "\n";
  file << "LOOKUP_TABLE default\n";

  // Write the actual pixel data
  if ( m_FileType == ASCII )
    {
    this->WriteBufferAsASCII(file, buffer, this->GetComponentType(),
                             this->GetImageSizeInComponents());
    }
  else //binary
    {
    file.write(static_cast<char*>(buffer), this->GetImageSizeInBytes());
    }
}

void VTKImageIO::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
}

} // end namespace itk
<|endoftext|>


<commit_before>#ifndef SILICIUM_SINK_HPP
#define SILICIUM_SINK_HPP

#include <silicium/override.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/filesystem/path.hpp>
#include <ostream>
#include <array>
#include <memory>

namespace Si
{
	template <class Element>
	struct sink
	{
		virtual ~sink()
		{
		}

		virtual boost::iterator_range<Element *> make_append_space(std::size_t size) = 0;
		virtual void flush_append_space() = 0;
		virtual void append(boost::iterator_range<Element const *> data) = 0;
	};

	template <class Element>
	struct flushable_sink : sink<Element>
	{
		virtual void flush() = 0;
	};

	template <class Element>
	void commit(sink<Element> &destination, std::size_t count)
	{
		destination.make_append_space(count);
		destination.flush_append_space();
	}

	template <class Element, class Buffer = std::array<Element, ((1U << 13U) / sizeof(Element))>>
	struct buffering_sink SILICIUM_FINAL : flushable_sink<Element>
	{
		explicit buffering_sink(sink<Element> &destination, Buffer buffer = Buffer())
			: m_destination(destination)
			, m_fallback_buffer(std::move(buffer))
			, m_buffer_used(0)
		{
		}

		boost::iterator_range<Element *> make_append_space(std::size_t size) SILICIUM_OVERRIDE
		{
			auto first_try = m_destination.make_append_space(size);
			if (!first_try.empty())
			{
				auto const copied = (std::min)(static_cast<std::ptrdiff_t>(m_buffer_used), first_try.size());
				std::copy(m_fallback_buffer.begin(), m_fallback_buffer.begin() + copied, first_try.begin());
				m_buffer_used = 0;
				return first_try;
			}
			m_buffer_used = (std::min)(size, m_fallback_buffer.size());
			return boost::make_iterator_range(m_fallback_buffer.data(), m_fallback_buffer.data() + m_buffer_used);
		}

		void flush_append_space() SILICIUM_OVERRIDE
		{
			if (m_buffer_used)
			{
				flush();
			}
			else
			{
				m_destination.flush_append_space();
			}
		}

		void append(boost::iterator_range<Element const *> data) SILICIUM_OVERRIDE
		{
			if (data.size() <= (m_fallback_buffer.size() - m_buffer_used))
			{
				boost::range::copy(data, m_fallback_buffer.begin() + m_buffer_used);
				m_buffer_used += data.size();
				return;
			}

			flush();
			m_destination.append(data);
		}

		void flush() SILICIUM_OVERRIDE
		{
			m_destination.append(boost::make_iterator_range(m_fallback_buffer.data(), m_fallback_buffer.data() + m_buffer_used));
			m_buffer_used = 0;
		}

	private:

		sink<Element> &m_destination;
		Buffer m_fallback_buffer;
		std::size_t m_buffer_used;
	};

	template <class Element, class OutputIterator>
	struct iterator_sink SILICIUM_FINAL : sink<Element>
	{
		explicit iterator_sink(OutputIterator out)
			: m_out(std::move(out))
		{
		}

		virtual boost::iterator_range<Element *> make_append_space(std::size_t) SILICIUM_OVERRIDE
		{
			return {};
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
		}

		virtual void append(boost::iterator_range<Element const *> data) SILICIUM_OVERRIDE
		{
			boost::range::copy(data, m_out);
		}

	private:

		OutputIterator m_out;
	};

	template <class Element, class OutputIterator>
	auto make_iterator_sink(OutputIterator out)
		-> iterator_sink<Element, typename std::decay<OutputIterator>::type>
	{
		return iterator_sink<Element, typename std::decay<OutputIterator>::type>(std::move(out));
	}

	template <class Container>
	auto make_container_sink(Container &destination)
		-> iterator_sink<typename Container::value_type, std::back_insert_iterator<Container>>
	{
		return make_iterator_sink<typename Container::value_type>(std::back_inserter(destination));
	}

	struct ostream_ref_sink SILICIUM_FINAL : flushable_sink<char>
	{
		ostream_ref_sink()
		{
		}

		explicit ostream_ref_sink(std::ostream &file)
		   : m_file(&file)
		{
		}

		virtual boost::iterator_range<char *> make_append_space(std::size_t) SILICIUM_OVERRIDE
		{
		   return {};
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
		}

		virtual void append(boost::iterator_range<char const *> data) SILICIUM_OVERRIDE
		{
			assert(m_file);
			m_file->write(data.begin(), data.size());
		}

		virtual void flush() SILICIUM_OVERRIDE
		{
			assert(m_file);
			m_file->flush();
		}

	private:

		std::ostream *m_file = nullptr;
	};

	struct ostream_sink SILICIUM_FINAL : flushable_sink<char>
	{
		//unique_ptr to make ostreams movable
		explicit ostream_sink(std::unique_ptr<std::ostream> file)
			: m_file(std::move(file))
		{
			m_file->exceptions(std::ios::failbit | std::ios::badbit);
		}

		virtual boost::iterator_range<char *> make_append_space(std::size_t) SILICIUM_OVERRIDE
		{
			return {};
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
		}

		virtual void append(boost::iterator_range<char const *> data) SILICIUM_OVERRIDE
		{
			m_file->write(data.begin(), data.size());
		}

		virtual void flush() SILICIUM_OVERRIDE
		{
			m_file->flush();
		}

	private:

		std::unique_ptr<std::ostream> m_file;
	};

	std::unique_ptr<flushable_sink<char>> make_file_sink(boost::filesystem::path const &name);

	template <class Element>
	struct auto_flush_sink SILICIUM_FINAL : sink<Element>
	{
		auto_flush_sink()
			: m_next(nullptr)
		{
		}

		explicit auto_flush_sink(flushable_sink<Element> &next)
			: m_next(&next)
		{
		}

		virtual boost::iterator_range<char *> make_append_space(std::size_t size) SILICIUM_OVERRIDE
		{
			assert(m_next);
			return m_next->make_append_space(size);
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
			assert(m_next);
			m_next->flush_append_space();
			m_next->flush();
		}

		virtual void append(boost::iterator_range<char const *> data) SILICIUM_OVERRIDE
		{
			assert(m_next);
			m_next->append(data);
			m_next->flush();
		}

	private:

		flushable_sink<Element> *m_next;
	};

	template <class Element>
	auto_flush_sink<Element> make_auto_flush_sink(flushable_sink<Element> &next)
	{
		return auto_flush_sink<Element>(next);
	}

	template <class Element>
	void append(Si::sink<Element> &out, std::basic_string<Element> const &str)
	{
		out.append(boost::make_iterator_range(str.data(), str.data() + str.size()));
	}

	template <class Element>
	void append(Si::sink<Element> &out, Element const *c_str)
	{
		out.append(boost::make_iterator_range(c_str, c_str + std::char_traits<Element>::length(c_str)));
	}

	template <class Element>
	void append(Si::sink<Element> &out, Element const &single)
	{
		out.append(boost::make_iterator_range(&single, &single + 1));
	}
}

#endif
<commit_msg>make buffering_sink copyable<commit_after>#ifndef SILICIUM_SINK_HPP
#define SILICIUM_SINK_HPP

#include <silicium/override.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/filesystem/path.hpp>
#include <ostream>
#include <array>
#include <memory>

namespace Si
{
	template <class Element>
	struct sink
	{
		virtual ~sink()
		{
		}

		virtual boost::iterator_range<Element *> make_append_space(std::size_t size) = 0;
		virtual void flush_append_space() = 0;
		virtual void append(boost::iterator_range<Element const *> data) = 0;
	};

	template <class Element>
	struct flushable_sink : sink<Element>
	{
		virtual void flush() = 0;
	};

	template <class Element>
	void commit(sink<Element> &destination, std::size_t count)
	{
		destination.make_append_space(count);
		destination.flush_append_space();
	}

	template <class Element, class Buffer = std::array<Element, ((1U << 13U) / sizeof(Element))>>
	struct buffering_sink SILICIUM_FINAL : flushable_sink<Element>
	{
		buffering_sink()
		{
		}

		explicit buffering_sink(sink<Element> &destination, Buffer buffer = Buffer())
			: m_destination(&destination)
			, m_fallback_buffer(std::move(buffer))
			, m_buffer_used(0)
		{
		}

		boost::iterator_range<Element *> make_append_space(std::size_t size) SILICIUM_OVERRIDE
		{
			assert(m_destination);
			auto first_try = m_destination->make_append_space(size);
			if (!first_try.empty())
			{
				auto const copied = (std::min)(static_cast<std::ptrdiff_t>(m_buffer_used), first_try.size());
				std::copy(m_fallback_buffer.begin(), m_fallback_buffer.begin() + copied, first_try.begin());
				m_buffer_used = 0;
				return first_try;
			}
			m_buffer_used = (std::min)(size, m_fallback_buffer.size());
			return boost::make_iterator_range(m_fallback_buffer.data(), m_fallback_buffer.data() + m_buffer_used);
		}

		void flush_append_space() SILICIUM_OVERRIDE
		{
			assert(m_destination);
			if (m_buffer_used)
			{
				flush();
			}
			else
			{
				m_destination->flush_append_space();
			}
		}

		void append(boost::iterator_range<Element const *> data) SILICIUM_OVERRIDE
		{
			assert(m_destination);
			if (data.size() <= (m_fallback_buffer.size() - m_buffer_used))
			{
				boost::range::copy(data, m_fallback_buffer.begin() + m_buffer_used);
				m_buffer_used += data.size();
				return;
			}

			flush();
			m_destination->append(data);
		}

		void flush() SILICIUM_OVERRIDE
		{
			assert(m_destination);
			m_destination->append(boost::make_iterator_range(m_fallback_buffer.data(), m_fallback_buffer.data() + m_buffer_used));
			m_buffer_used = 0;
		}

	private:

		sink<Element> *m_destination = nullptr;
		Buffer m_fallback_buffer;
		std::size_t m_buffer_used;
	};

	template <class Element, class OutputIterator>
	struct iterator_sink SILICIUM_FINAL : sink<Element>
	{
		explicit iterator_sink(OutputIterator out)
			: m_out(std::move(out))
		{
		}

		virtual boost::iterator_range<Element *> make_append_space(std::size_t) SILICIUM_OVERRIDE
		{
			return {};
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
		}

		virtual void append(boost::iterator_range<Element const *> data) SILICIUM_OVERRIDE
		{
			boost::range::copy(data, m_out);
		}

	private:

		OutputIterator m_out;
	};

	template <class Element, class OutputIterator>
	auto make_iterator_sink(OutputIterator out)
		-> iterator_sink<Element, typename std::decay<OutputIterator>::type>
	{
		return iterator_sink<Element, typename std::decay<OutputIterator>::type>(std::move(out));
	}

	template <class Container>
	auto make_container_sink(Container &destination)
		-> iterator_sink<typename Container::value_type, std::back_insert_iterator<Container>>
	{
		return make_iterator_sink<typename Container::value_type>(std::back_inserter(destination));
	}

	struct ostream_ref_sink SILICIUM_FINAL : flushable_sink<char>
	{
		ostream_ref_sink()
		{
		}

		explicit ostream_ref_sink(std::ostream &file)
		   : m_file(&file)
		{
		}

		virtual boost::iterator_range<char *> make_append_space(std::size_t) SILICIUM_OVERRIDE
		{
		   return {};
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
		}

		virtual void append(boost::iterator_range<char const *> data) SILICIUM_OVERRIDE
		{
			assert(m_file);
			m_file->write(data.begin(), data.size());
		}

		virtual void flush() SILICIUM_OVERRIDE
		{
			assert(m_file);
			m_file->flush();
		}

	private:

		std::ostream *m_file = nullptr;
	};

	struct ostream_sink SILICIUM_FINAL : flushable_sink<char>
	{
		//unique_ptr to make ostreams movable
		explicit ostream_sink(std::unique_ptr<std::ostream> file)
			: m_file(std::move(file))
		{
			m_file->exceptions(std::ios::failbit | std::ios::badbit);
		}

		virtual boost::iterator_range<char *> make_append_space(std::size_t) SILICIUM_OVERRIDE
		{
			return {};
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
		}

		virtual void append(boost::iterator_range<char const *> data) SILICIUM_OVERRIDE
		{
			m_file->write(data.begin(), data.size());
		}

		virtual void flush() SILICIUM_OVERRIDE
		{
			m_file->flush();
		}

	private:

		std::unique_ptr<std::ostream> m_file;
	};

	std::unique_ptr<flushable_sink<char>> make_file_sink(boost::filesystem::path const &name);

	template <class Element>
	struct auto_flush_sink SILICIUM_FINAL : sink<Element>
	{
		auto_flush_sink()
			: m_next(nullptr)
		{
		}

		explicit auto_flush_sink(flushable_sink<Element> &next)
			: m_next(&next)
		{
		}

		virtual boost::iterator_range<char *> make_append_space(std::size_t size) SILICIUM_OVERRIDE
		{
			assert(m_next);
			return m_next->make_append_space(size);
		}

		virtual void flush_append_space() SILICIUM_OVERRIDE
		{
			assert(m_next);
			m_next->flush_append_space();
			m_next->flush();
		}

		virtual void append(boost::iterator_range<char const *> data) SILICIUM_OVERRIDE
		{
			assert(m_next);
			m_next->append(data);
			m_next->flush();
		}

	private:

		flushable_sink<Element> *m_next;
	};

	template <class Element>
	auto_flush_sink<Element> make_auto_flush_sink(flushable_sink<Element> &next)
	{
		return auto_flush_sink<Element>(next);
	}

	template <class Element>
	void append(Si::sink<Element> &out, std::basic_string<Element> const &str)
	{
		out.append(boost::make_iterator_range(str.data(), str.data() + str.size()));
	}

	template <class Element>
	void append(Si::sink<Element> &out, Element const *c_str)
	{
		out.append(boost::make_iterator_range(c_str, c_str + std::char_traits<Element>::length(c_str)));
	}

	template <class Element>
	void append(Si::sink<Element> &out, Element const &single)
	{
		out.append(boost::make_iterator_range(&single, &single + 1));
	}
}

#endif
<|endoftext|>