<commit_before>//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Green Enery Corp licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
#include "StartupTasks.h"

#include "APDU.h"
#include "ObjectReadIterator.h"
#include "PointClass.h"
#include <APL/ITimeSource.h>
#include <APL/Logger.h>

namespace apl
{
namespace dnp
{

/* ------ Clear Restart ------- */

ClearRestartIIN::ClearRestartIIN(Logger* apLogger) :
	SimpleRspBase(apLogger)
{}

void ClearRestartIIN::ConfigureRequest(APDU& arAPDU)
{
	arAPDU.Set(FC_WRITE);
	Group80Var1* pObj = Group80Var1::Inst(); // Internal indications object
	ObjectWriteIterator i = arAPDU.WriteContiguous(pObj, 7, 7); // index 7 == device restart
	pObj->Write(*i, 7, 7, false);
}

/* ------ Configure Unsol ------- */

ConfigureUnsol::ConfigureUnsol(Logger* apLogger) :
	SimpleRspBase(apLogger),
	mIsEnable(false),
	mClassMask(0)
{}

void ConfigureUnsol::Set(bool aIsEnable, int aClassMask)
{
	mIsEnable = aIsEnable;
	mClassMask = aClassMask;
}

void ConfigureUnsol::ConfigureRequest(APDU& arAPDU)
{
	arAPDU.Set(mIsEnable ? FC_ENABLE_UNSOLICITED : FC_DISABLE_UNSOLICITED);
	if(mClassMask & PC_CLASS_1) arAPDU.DoPlaceholderWrite(Group60Var2::Inst());
	if(mClassMask & PC_CLASS_2) arAPDU.DoPlaceholderWrite(Group60Var3::Inst());
	if(mClassMask & PC_CLASS_3) arAPDU.DoPlaceholderWrite(Group60Var4::Inst());
}

/* ------ Time Sync ------- */

TimeSync::TimeSync(Logger* apLogger, ITimeSource* apTimeSrc) :
	SingleRspBase(apLogger),
	mpTimeSrc(apTimeSrc),
	mDelay(-1)
{}

void TimeSync::Init()
{
	mDelay = -1;
}

void TimeSync::ConfigureRequest(APDU& arAPDU)
{
	if(mDelay < 0) {
		arAPDU.Set(FC_DELAY_MEASURE);
		mStart = mpTimeSrc->GetUTC();
	}
	else {
		arAPDU.Set(FC_WRITE);
		ObjectWriteIterator owi = arAPDU.WriteContiguous(Group50Var1::Inst(), 0, 0, QC_1B_CNT);
		Group50Var1::Inst()->mTime.Set(*owi, mpTimeSrc->GetTimeStampUTC() + mDelay);
	}
}

TaskResult TimeSync::_OnFinalResponse(const APDU& arAPDU)
{
	if(mDelay < 0) {
		ptime now = mpTimeSrc->GetUTC();

		HeaderReadIterator hri = arAPDU.BeginRead();
		if(hri.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexcpected header count");
			return TR_FAIL;
		}

		if(!hri->GetBaseObject()->Equals(Group52Var2::Inst())) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexpected object: " << hri->GetBaseObject()->Name());
			return TR_FAIL;
		}

		ObjectReadIterator ori = hri.BeginRead();
		if(ori.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas got more than 1 object in response");
			return TR_FAIL;
		}

		millis_t send_rcv_time = (now - mStart).total_milliseconds();
		millis_t rtu_turn_around = Group52Var2::Inst()->mTime.Get(*ori);

		// The later shouldn't happen, but could cause a negative delay which would
		// result in a weird time setting
		mDelay = (send_rcv_time >= rtu_turn_around) ? (send_rcv_time - rtu_turn_around) / 2 : 0;

		return TR_CONTINUE;
	}
	else {
		return TR_SUCCESS;
	}
}

}
} //ens ns

<commit_msg>Fix for 'malformed packet' during session startup<commit_after>//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Green Enery Corp licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
#include "StartupTasks.h"

#include "APDU.h"
#include "ObjectReadIterator.h"
#include "PointClass.h"
#include <APL/ITimeSource.h>
#include <APL/Logger.h>

namespace apl
{
namespace dnp
{

/* ------ Clear Restart ------- */

ClearRestartIIN::ClearRestartIIN(Logger* apLogger) :
	SimpleRspBase(apLogger)
{}

void ClearRestartIIN::ConfigureRequest(APDU& arAPDU)
{
	arAPDU.Set(FC_WRITE);
	Group80Var1* pObj = Group80Var1::Inst(); // Internal indications object
	ObjectWriteIterator i = arAPDU.WriteContiguous(pObj, 7, 7); // index 7 == device restart
	pObj->Write(*i, 7, 7, false);
}

/* ------ Configure Unsol ------- */

ConfigureUnsol::ConfigureUnsol(Logger* apLogger) :
	SimpleRspBase(apLogger),
	mIsEnable(false),
	mClassMask(0)
{}

void ConfigureUnsol::Set(bool aIsEnable, int aClassMask)
{
	mIsEnable = aIsEnable;
	mClassMask = aClassMask;
}

void ConfigureUnsol::ConfigureRequest(APDU& arAPDU)
{
	arAPDU.Set((mIsEnable && mClassMask != 0) ? FC_ENABLE_UNSOLICITED : FC_DISABLE_UNSOLICITED);
	if(mClassMask & PC_CLASS_1) arAPDU.DoPlaceholderWrite(Group60Var2::Inst());
	if(mClassMask & PC_CLASS_2) arAPDU.DoPlaceholderWrite(Group60Var3::Inst());
	if(mClassMask & PC_CLASS_3) arAPDU.DoPlaceholderWrite(Group60Var4::Inst());
}

/* ------ Time Sync ------- */

TimeSync::TimeSync(Logger* apLogger, ITimeSource* apTimeSrc) :
	SingleRspBase(apLogger),
	mpTimeSrc(apTimeSrc),
	mDelay(-1)
{}

void TimeSync::Init()
{
	mDelay = -1;
}

void TimeSync::ConfigureRequest(APDU& arAPDU)
{
	if(mDelay < 0) {
		arAPDU.Set(FC_DELAY_MEASURE);
		mStart = mpTimeSrc->GetUTC();
	}
	else {
		arAPDU.Set(FC_WRITE);
		ObjectWriteIterator owi = arAPDU.WriteContiguous(Group50Var1::Inst(), 0, 0, QC_1B_CNT);
		Group50Var1::Inst()->mTime.Set(*owi, mpTimeSrc->GetTimeStampUTC() + mDelay);
	}
}

TaskResult TimeSync::_OnFinalResponse(const APDU& arAPDU)
{
	if(mDelay < 0) {
		ptime now = mpTimeSrc->GetUTC();

		HeaderReadIterator hri = arAPDU.BeginRead();
		if(hri.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexcpected header count");
			return TR_FAIL;
		}

		if(!hri->GetBaseObject()->Equals(Group52Var2::Inst())) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexpected object: " << hri->GetBaseObject()->Name());
			return TR_FAIL;
		}

		ObjectReadIterator ori = hri.BeginRead();
		if(ori.Count() != 1) {
			LOG_BLOCK(LEV_WARNING, "DelayMeas got more than 1 object in response");
			return TR_FAIL;
		}

		millis_t send_rcv_time = (now - mStart).total_milliseconds();
		millis_t rtu_turn_around = Group52Var2::Inst()->mTime.Get(*ori);

		// The later shouldn't happen, but could cause a negative delay which would
		// result in a weird time setting
		mDelay = (send_rcv_time >= rtu_turn_around) ? (send_rcv_time - rtu_turn_around) / 2 : 0;

		return TR_CONTINUE;
	}
	else {
		return TR_SUCCESS;
	}
}

}
} //ens ns

<|endoftext|>


<commit_before>/*
 * Portability.hh
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#ifndef _LOG4CPP_PORTABILITY_HH
#define _LOG4CPP_PORTABILITY_HH

#if defined (_MSC_VER) || defined(__BORLANDC__)
#    if defined (LOG4CPP_STLPORT_AND_BOOST_BUILD)
#        include <log4cpp/config-win32-stlport-boost.h>
#    else
#        include <log4cpp/config-win32.h>
#    endif
#else
#if defined(__OPENVMS__)
#    include <log4cpp/config-openvms.h>
#else
#   if defined(__MINGW32__)
#       include <log4cpp/config-MinGW32.h>
#   else
#       include <log4cpp/config.h>
#   endif
#endif
#endif

#include <log4cpp/Export.hh>

#if defined(_MSC_VER)
#    pragma warning( disable : 4786 ) // 255 char debug symbol limit
#    pragma warning( disable : 4290 ) // throw specifier not implemented
#    pragma warning( disable : 4251 ) // "class XXX should be exported"
#endif

#ifndef LOG4CPP_HAVE_SSTREAM
#include <strstream>
namespace std {
    class LOG4CPP_EXPORT ostringstream : public ostrstream {
        public:
        std::string str();
    };
}
#endif

#endif
<commit_msg>[intern] changes by Tan Meng YUE to have the cmake stuff available<commit_after>/*
 * Portability.hh
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#ifndef _LOG4CPP_PORTABILITY_HH
#define _LOG4CPP_PORTABILITY_HH

#if defined (_MSC_VER) || defined(__BORLANDC__)
#    if defined (LOG4CPP_STLPORT_AND_BOOST_BUILD)
#        include <log4cpp/config-win32-stlport-boost.h>
#    else
#        include <log4cpp/config-win32.h>
#    endif
#else
#if defined(__OPENVMS__)
#    include <log4cpp/config-openvms.h>
#else
#   if defined(__MINGW32__)
#       include <log4cpp/config-MinGW32.h>
#   else
#       include <log4cpp/config.h>
#   endif
#endif
#endif

#include <log4cpp/Export.hh>

#if defined(_MSC_VER)
#    pragma warning( disable : 4786 ) // 255 char debug symbol limit
#    pragma warning( disable : 4290 ) // throw specifier not implemented
#    pragma warning( disable : 4251 ) // "class XXX should be exported"
#endif

#ifdef __APPLE__
#  include <sstream>
#else
#  ifndef LOG4CPP_HAVE_SSTREAM
#    include <strstream>
     namespace std {
       class LOG4CPP_EXPORT ostringstream : public ostrstream {
       public:
	 std::string str();
       };
     };
#  endif // LOG4CPP_HAVE_SSTREAM
#endif // _APPLE_

#endif
<|endoftext|>


<commit_before>#pragma once
#include <vector>
#include <chrono>
#include <initializer_list>

namespace mos {

/** Container. */
template<class T>
class Container {
public:
  using Items = std::vector<T>;

  Container() = default;

  template<class It>
  Container(const std::initializer_list<It> list): Container(list.begin(), list.end()){}

  template<class It>
  Container(It begin, It end) {
    assign(begin, end);
  }

  template<class It>
  void assign(It begin, It end){
    items_.assign(begin, end);
  }
  typename Items::iterator begin() {
    return items_.begin();
  }
  typename Items::iterator end() {
    return items_.end();
  }
  typename Items::const_iterator begin() const {
    return items_.begin();
  }
  typename Items::const_iterator end() const {
    return items_.end();
  }
  typename Items::reference operator[](typename Items::size_type pos){
    return items_[pos];
  }
  typename Items::const_reference operator[](typename Items::size_type pos) const {
    return items_[pos];
  }
  typename Items::size_type size() const {
    return items_.size();
  }
  typename Items::reference back() {
    return items_.back();
  }
  const T * data() const noexcept {
    return items_.data();
  }
  void clear() {
    items_.clear();
  }
  void push_back(const T &item){
    items_.push_back(item);
  }
private:
  Items items_;
};

}<commit_msg>Insert container.<commit_after>#pragma once
#include <vector>
#include <chrono>
#include <initializer_list>

namespace mos {

/** Container. */
template<class T>
class Container {
public:
  using Items = std::vector<T>;

  Container() = default;

  template<class It>
  Container(const std::initializer_list<It> list): Container(list.begin(), list.end()){}

  template<class It>
  Container(It begin, It end) {
    assign(begin, end);
  }

  template<class It>
  void assign(It begin, It end){
    items_.assign(begin, end);
  }

  template<class It>
  typename Items::iterator insert(typename Items::const_iterator pos, It begin, It end){
    return items_.insert(pos, begin, end);
  }

  typename Items::iterator begin() {
    return items_.begin();
  }
  typename Items::iterator end() {
    return items_.end();
  }
  typename Items::const_iterator begin() const {
    return items_.begin();
  }
  typename Items::const_iterator end() const {
    return items_.end();
  }
  typename Items::reference operator[](typename Items::size_type pos){
    return items_[pos];
  }
  typename Items::const_reference operator[](typename Items::size_type pos) const {
    return items_[pos];
  }
  typename Items::size_type size() const {
    return items_.size();
  }
  typename Items::reference back() {
    return items_.back();
  }
  const T * data() const noexcept {
    return items_.data();
  }
  void clear() {
    items_.clear();
  }

  void push_back(const T &item){
    items_.push_back(item);
  }
private:
  Items items_;
};

}<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2014 Conrado Miranda

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#ifndef __MPI_OBJECT_ARCHIVE_HPP__
#define __MPI_OBJECT_ARCHIVE_HPP__

#include <boost/mpi.hpp>
#include <map>
#include <vector>
#include <unordered_map>

#include "object_archive.hpp"

template <class Key>
class MPIObjectArchive: public ObjectArchive<Key> {
  public:
    struct Tags {
      int alive = 0;
      int invalidated = 1;
      int inserted = 2;
      int request = 3;
      int response = 4;
      int response_data = 5;
    };

    MPIObjectArchive(boost::mpi::communicator* world,
        bool record_everything = false);

    MPIObjectArchive(Tags const& tags, boost::mpi::communicator* world,
        bool record_everything = false);

    ~MPIObjectArchive();

    virtual void remove(Key const& key);

    virtual size_t insert_raw(Key const& key, std::string&& data,
        bool keep_in_buffer = true);

    virtual size_t load_raw(Key const& key, std::string& data,
        bool keep_in_buffer = true);

    void mpi_process();

  private:
    struct Request {
      Key key;
      int counter;

      template<class Archive>
      void serialize(Archive& ar, const unsigned int version) {
        ar & key;
        ar & counter;
      }

      bool operator<(Request const& other) const {
        return key < other.key || (key == other.key && counter < other.counter);
      }
    };

    struct Response {
      Request request;
      bool found;

      template<class Archive>
      void serialize(Archive& ar, const unsigned int version) {
        ar & request;
        ar & found;
      }
    };

    struct ResponseData {
      Request request;
      std::string data;

      template<class Archive>
      void serialize(Archive& ar, const unsigned int version) {
        ar & request;
        ar & data;
      }
    };

    void process_alive(int source, bool alive);
    void process_invalidated(int source, Key const& key);
    void process_inserted(int source, Key const& key);
    void process_request(int source, Request const& request);
    boost::optional<std::string> get_response(int source, int n_waiting,
        Request& request);

    template <class T>
    void broadcast_others(int tag, T const& val, bool check_alive = true);

    template <class T>
    boost::optional<boost::mpi::status>
    non_blocking_recv(int source, int tag, T& value);

    Tags tags_;
    boost::mpi::communicator* world_;
    bool record_everything_;
    std::vector<bool> alive_; // By default, considers itself dead
    int request_counter_;

    std::map<Request, Request*> alive_requests_;
    std::unordered_map<Request*, int> requests_source_;
    std::unordered_map<Request*, int> requests_waiting_;
    std::unordered_map<Request*, int> requests_found_;
    std::unordered_map<Request*, std::string> responses_data_;
};

#include "mpi_object_archive_impl.hpp"

#endif
<commit_msg>[mpi] Started adding documentation.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2014 Conrado Miranda

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// This file defines an implementation of the ObjectArchive that allows very
// loose consistency to be kept between archives in a MPI environment.
//
// The three basic operations (insert, load and remove) are communicated to
// object instances in other MPI nodes, so data can be transparently shared.
// However, the methods to check if a value is present (is_available and
// available_objects) aren't mapped through MPI, as their returned values may
// become incorrect right after the call. Hence they only provide local values.
// In case this information is required, an MPI archive can be instructed to
// store every remove value.
//
// The objects require 6 different tags to communicate among themselves, which
// should be the same for all but are personalizable by the user, and uses
// boost::mpi. The communicator given to the constructor must be kept valid
// until the archive is destroyed.
//
// Threading support: to allow the archive to be used by multiple threads, set
// ENABLE_THREADS. This should place mutex at the right places for consistency.
//
// Example:
// MPIObjectArchive<std::string> ar(&world);
// ar.init("path/to/file");
// ar.set_buffer_size("1.5G");
//
// ar.insert("filename", filedata);
// [do some stuff]
// ar.load("filename", filedata);
// [filedata has the previous value again]
// ar.remove("filename");
// [filedata keeps its value]

#ifndef __MPI_OBJECT_ARCHIVE_HPP__
#define __MPI_OBJECT_ARCHIVE_HPP__

#include <boost/mpi.hpp>
#include <map>
#include <vector>
#include <unordered_map>

#include "object_archive.hpp"

template <class Key>
class MPIObjectArchive: public ObjectArchive<Key> {
  public:
    struct Tags {
      int alive = 0;
      int invalidated = 1;
      int inserted = 2;
      int request = 3;
      int response = 4;
      int response_data = 5;
    };

    MPIObjectArchive(boost::mpi::communicator* world,
        bool record_everything = false);

    MPIObjectArchive(Tags const& tags, boost::mpi::communicator* world,
        bool record_everything = false);

    ~MPIObjectArchive();

    virtual void remove(Key const& key);

    virtual size_t insert_raw(Key const& key, std::string&& data,
        bool keep_in_buffer = true);

    virtual size_t load_raw(Key const& key, std::string& data,
        bool keep_in_buffer = true);

    void mpi_process();

  private:
    struct Request {
      Key key;
      int counter;

      template<class Archive>
      void serialize(Archive& ar, const unsigned int version) {
        ar & key;
        ar & counter;
      }

      bool operator<(Request const& other) const {
        return key < other.key || (key == other.key && counter < other.counter);
      }
    };

    struct Response {
      Request request;
      bool found;

      template<class Archive>
      void serialize(Archive& ar, const unsigned int version) {
        ar & request;
        ar & found;
      }
    };

    struct ResponseData {
      Request request;
      std::string data;

      template<class Archive>
      void serialize(Archive& ar, const unsigned int version) {
        ar & request;
        ar & data;
      }
    };

    void process_alive(int source, bool alive);
    void process_invalidated(int source, Key const& key);
    void process_inserted(int source, Key const& key);
    void process_request(int source, Request const& request);
    boost::optional<std::string> get_response(int source, int n_waiting,
        Request& request);

    template <class T>
    void broadcast_others(int tag, T const& val, bool check_alive = true);

    template <class T>
    boost::optional<boost::mpi::status>
    non_blocking_recv(int source, int tag, T& value);

    Tags tags_;
    boost::mpi::communicator* world_;
    bool record_everything_;
    std::vector<bool> alive_; // By default, considers itself dead
    int request_counter_;

    std::map<Request, Request*> alive_requests_;
    std::unordered_map<Request*, int> requests_source_;
    std::unordered_map<Request*, int> requests_waiting_;
    std::unordered_map<Request*, int> requests_found_;
    std::unordered_map<Request*, std::string> responses_data_;
};

#include "mpi_object_archive_impl.hpp"

#endif
<|endoftext|>


<commit_before>/*!
    \file latch.cpp
    \brief Latch synchronization primitive implementation
    \author Ivan Shynkarenka
    \date 25.03.2016
    \copyright MIT License
*/

#include "threads/latch.h"

namespace CppCommon {

void Latch::Reset(int threads) noexcept
{
    assert((threads > 0) && "Latch threads counter must be greater than zero!");

    std::lock_guard<std::mutex> lock(_mutex);

    // Reset the latch threads counter with a new value
    _threads = threads;
}

bool Latch::CountDown(std::unique_lock<std::mutex>& lock) noexcept
{
    // Count down the latch threads counter and check its value
    if (--_threads == 0)
    {
        // Increase the current latch generation
        ++_generation;

        // Notify all waiting threads
        _cond.notify_all();

        // Wait for the next latch generation
        return true;
    }

    // Notify each of remaining threads
    return false;
}

void Latch::CountDown() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Count down the latch threads counter
    CountDown(lock);
}

void Latch::CountDownAndWait() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Remember the current latch generation
    int generation = _generation;

    // Count down the latch threads counter
    if (CountDown(lock))
        return;

    // Wait for the next latch generation
    _cond.wait(lock, [=, this]() { return generation != _generation; });
}

void Latch::Wait() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Check the latch threads counter value
    if (_threads == 0)
        return;

    // Remember the current latch generation
    int generation = _generation;

    // Wait for the next latch generation
    _cond.wait(lock, [=, this]() { return generation != _generation; });
}

bool Latch::TryWait() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Check the latch threads counter value
    return (_threads == 0);
}

} // namespace CppCommon
<commit_msg>Fix linux build<commit_after>/*!
    \file latch.cpp
    \brief Latch synchronization primitive implementation
    \author Ivan Shynkarenka
    \date 25.03.2016
    \copyright MIT License
*/

#include "threads/latch.h"

namespace CppCommon {

void Latch::Reset(int threads) noexcept
{
    assert((threads > 0) && "Latch threads counter must be greater than zero!");

    std::lock_guard<std::mutex> lock(_mutex);

    // Reset the latch threads counter with a new value
    _threads = threads;
}

bool Latch::CountDown(std::unique_lock<std::mutex>& lock) noexcept
{
    // Count down the latch threads counter and check its value
    if (--_threads == 0)
    {
        // Increase the current latch generation
        ++_generation;

        // Notify all waiting threads
        _cond.notify_all();

        // Wait for the next latch generation
        return true;
    }

    // Notify each of remaining threads
    return false;
}

void Latch::CountDown() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Count down the latch threads counter
    CountDown(lock);
}

void Latch::CountDownAndWait() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Remember the current latch generation
    int generation = _generation;

    // Count down the latch threads counter
    if (CountDown(lock))
        return;

    // Wait for the next latch generation
    _cond.wait(lock, [&, this]() { return generation != _generation; });
}

void Latch::Wait() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Check the latch threads counter value
    if (_threads == 0)
        return;

    // Remember the current latch generation
    int generation = _generation;

    // Wait for the next latch generation
    _cond.wait(lock, [&, this]() { return generation != _generation; });
}

bool Latch::TryWait() noexcept
{
    std::unique_lock<std::mutex> lock(_mutex);

    // Check the latch threads counter value
    return (_threads == 0);
}

} // namespace CppCommon
<|endoftext|>


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

  nomlib - C++11 cross-platform game engine

Copyright (c) 2013, Jeffrey Carpenter <jeffrey.carp@gmail.com>
All rights reserved.

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

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

******************************************************************************/
#ifndef NOMLIB_RGBA_COLOR4_HPP
#define NOMLIB_RGBA_COLOR4_HPP

#include <algorithm>

#include "nomlib/config.hpp"

namespace nom {

/// Delimiter character to use with << operator
const std::string COLOR_DELIMITER = ", ";

/// 100% transparent alpha channel value
const int ALPHA_TRANSPARENT = 0;

/// 100% opaque alpha channel value
const int ALPHA_OPAQUE = 255;

/// \brief RGBA color
///
/// \todo Implement lesser than, greater than and so on operators?
template <typename T>
class Color4
{
  public:
    /// Default constructor; sets the color to their respective defaults
    Color4 ( void ) : red ( 0 ), green ( 0 ), blue ( 0 ),
      alpha ( ALPHA_OPAQUE ) {}

    /// Destructor
    ~Color4 ( void ) {}

    /// Copy constructor
    template <typename U>
    Color4 ( const Color4<U>& copy )
    {
      this->red = static_cast<T> ( copy.red );
      this->green = static_cast<T> ( copy.green );
      this->blue = static_cast<T> ( copy.blue );
      this->alpha = static_cast<T> ( copy.alpha );
    }

    /// Constructor variant for setting a color using RGB values
    Color4 ( T r, T g, T b ) : red ( r ), green ( g ),
      blue ( b ), alpha ( ALPHA_OPAQUE ) {}

    /// Constructor variant for setting a color using RGBA values
    Color4 ( T red, T green, T blue, T alpha ) : red ( red ),
      green ( green ), blue ( blue ), alpha ( alpha ) {}

    /// Copy assignment operator
    inline Color4<T>& operator = ( const Color4<T>& other )
    {
      this->red = other.red;
      this->green = other.green;
      this->blue = other.blue;
      this->alpha = other.alpha;

      return *this;
    }

    /// Convenience getter for obtaining a copy of this object
    inline const Color4<T>& get ( void ) const
    {
      return *this;
    }

  public:
    T red;
    T green;
    T blue;
    T alpha;

    /// Reference alias for red instance variable
    T& r = red;

    /// Reference alias for green instance variable
    T& g = green;

    /// Reference alias for blue instance variable
    T& b = blue;

    /// Reference alias for alpha instance variable
    T& a = alpha;
};

/// Pretty print the color using the following format string:
///
/// <color.red>, <color.green>, <color.blue>, <color.alpha>
///
/// This will look like:
///
/// 99, 144, 255, 128
inline std::ostream& operator << ( std::ostream& os, const Color4<uint8>& color )
{
  os << static_cast<int> ( color.red ) << COLOR_DELIMITER
     << static_cast<int> ( color.green ) << COLOR_DELIMITER
     << static_cast<int> ( color.blue ) << COLOR_DELIMITER
     << static_cast<int> ( color.alpha );
  return os;
}
{
  os << static_cast<T> ( color.red ) << COLOR_DELIMITER
     << static_cast<T> ( color.green ) << COLOR_DELIMITER
     << static_cast<T> ( color.blue ) << COLOR_DELIMITER
     << static_cast<T> ( color.alpha );
  return os;
}

template <typename T>
inline bool operator == ( const Color4<T>& left, const Color4<T>& right )
{
  return ( left.red == right.red ) &&
         ( left.green == right.green ) &&
         ( left.blue == right.blue ) &&
         ( left.alpha == right.alpha );
}

template <typename T>
inline bool operator != ( const Color4<T>& left, const Color4<T>& right )
{
  return ! ( left == right );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator + ( const Color4<T>& left, const Color4<T>& right )
{
  return Color4<T> ( static_cast<T> ( std::min ( left.red + right.red, 255 ) ),
                    static_cast<T> ( std::min ( left.green + right.green, 255 ) ),
                    static_cast<T> ( std::min ( left.blue + right.blue, 255 ) ),
                    static_cast<T> ( std::min ( left.alpha + right.alpha, 255 ) )
                  );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator ++ ( Color4<T>& left )
{
  return Color4<T> ( static_cast<T> ( left.red-- ),
                    static_cast<T> ( left.green-- ),
                    static_cast<T> ( left.blue-- ),
                    static_cast<T> ( left.alpha-- )
                );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator - ( const Color4<T>& left, const Color4<T>& right )
{
  return Color4<T> ( static_cast<T> ( std::min ( left.red - right.red, 255 ) ),
                    static_cast<T> ( std::min ( left.green - right.green, 255 ) ),
                    static_cast<T> ( std::min ( left.blue - right.blue, 255 ) ),
                    static_cast<T> ( std::min ( left.alpha - right.alpha, 255 ) )
                  );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator -- ( Color4<T>& left )
{
  return Color4<T> ( static_cast<T> ( left.red-- ),
                    static_cast<T> ( left.green-- ),
                    static_cast<T> ( left.blue-- ),
                    static_cast<T> ( left.alpha-- )
                  );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator * ( const Color4<T>& left, const Color4<T>& right )
{
  return Color4<T> ( static_cast<T> ( left.red * right.red / 255 ),
                    static_cast<T> ( left.green * right.green / 255 ),
                    static_cast<T> ( left.blue * right.blue / 255 ),
                    static_cast<T> ( left.alpha * right.alpha / 255 )
                  );
}

template <typename T>
inline Color4<T>& operator += ( Color4<T>& left, const Color4<T>& right )
{
  return left = left + right;
}

template <typename T>
inline Color4<T>& operator -= ( Color4<T>& left, const Color4<T>& right )
{
  return left = left - right;
}

template <typename T>
inline Color4<T>& operator *= ( Color4<T>& left, const Color4<T>& right )
{
  return left = left * right;
}

typedef Color4<uint8> Color4u;
typedef Color4<float> Color4f;

} // namespace nom

/// Primary colors
#define NOM_COLOR4U_BLACK \
  nom::Color4u ( 0, 0, 0, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_WHITE \
  nom::Color4u ( 255, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_RED \
  nom::Color4u ( 255, 0, 0, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_GREEN \
  nom::Color4u ( 0, 255, 0, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_BLUE \
  nom::Color4u ( 0, 0, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_YELLOW \
  nom::Color4u ( 255, 255, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_MAGENTA \
  nom::Color4u ( 255, 0, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_CYAN \
  nom::Color4u ( 0, 255, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_SILVER \
  nom::Color4u ( 192, 192, 192, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_PURPLE \
  nom::Color4u ( 128, 0, 128, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_ORANGE \
  nom::Color4u ( 255, 165, 0, nom::ALPHA_OPAQUE )

/// Additional colors
#define NOM_COLOR4U_LIGHT_GRAY \
  nom::Color4u ( 99, 99, 99, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_GRAY \
  nom::Color4u ( 67, 67, 67, nom::ALPHA_OPAQUE )

/// Light magenta color key
#define NOM_COLOR4U_PRIMARY_COLORKEY \
  nom::Color4u ( 110, 144, 190, nom::ALPHA_OPAQUE )

/// Sky blue color key
#define NOM_COLOR4U_SECONDARY_COLORKEY \
  nom::Color4u ( 223, 75, 255, nom::ALPHA_OPAQUE )

#endif // include guard defined
<commit_msg>Color4: Introduce << operator for Color4f<commit_after>/******************************************************************************

  nomlib - C++11 cross-platform game engine

Copyright (c) 2013, Jeffrey Carpenter <jeffrey.carp@gmail.com>
All rights reserved.

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

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

******************************************************************************/
#ifndef NOMLIB_RGBA_COLOR4_HPP
#define NOMLIB_RGBA_COLOR4_HPP

#include <algorithm>

#include "nomlib/config.hpp"

namespace nom {

/// Delimiter character to use with << operator
const std::string COLOR_DELIMITER = ", ";

/// 100% transparent alpha channel value
const int ALPHA_TRANSPARENT = 0;

/// 100% opaque alpha channel value
const int ALPHA_OPAQUE = 255;

/// \brief RGBA color
///
/// \todo Implement lesser than, greater than and so on operators?
template <typename T>
class Color4
{
  public:
    /// Default constructor; sets the color to their respective defaults
    Color4 ( void ) : red ( 0 ), green ( 0 ), blue ( 0 ),
      alpha ( ALPHA_OPAQUE ) {}

    /// Destructor
    ~Color4 ( void ) {}

    /// Copy constructor
    template <typename U>
    Color4 ( const Color4<U>& copy )
    {
      this->red = static_cast<T> ( copy.red );
      this->green = static_cast<T> ( copy.green );
      this->blue = static_cast<T> ( copy.blue );
      this->alpha = static_cast<T> ( copy.alpha );
    }

    /// Constructor variant for setting a color using RGB values
    Color4 ( T r, T g, T b ) : red ( r ), green ( g ),
      blue ( b ), alpha ( ALPHA_OPAQUE ) {}

    /// Constructor variant for setting a color using RGBA values
    Color4 ( T red, T green, T blue, T alpha ) : red ( red ),
      green ( green ), blue ( blue ), alpha ( alpha ) {}

    /// Copy assignment operator
    inline Color4<T>& operator = ( const Color4<T>& other )
    {
      this->red = other.red;
      this->green = other.green;
      this->blue = other.blue;
      this->alpha = other.alpha;

      return *this;
    }

    /// Convenience getter for obtaining a copy of this object
    inline const Color4<T>& get ( void ) const
    {
      return *this;
    }

  public:
    T red;
    T green;
    T blue;
    T alpha;

    /// Reference alias for red instance variable
    T& r = red;

    /// Reference alias for green instance variable
    T& g = green;

    /// Reference alias for blue instance variable
    T& b = blue;

    /// Reference alias for alpha instance variable
    T& a = alpha;
};

/// Pretty print the color using the following format string:
///
/// <color.red>, <color.green>, <color.blue>, <color.alpha>
///
/// This will look like:
///
/// 99, 144, 255, 128
inline std::ostream& operator << ( std::ostream& os, const Color4<uint8>& color )
{
  os << static_cast<int> ( color.red ) << COLOR_DELIMITER
     << static_cast<int> ( color.green ) << COLOR_DELIMITER
     << static_cast<int> ( color.blue ) << COLOR_DELIMITER
     << static_cast<int> ( color.alpha );
  return os;
}

inline std::ostream& operator << ( std::ostream& os, const Color4<float>& color )
{
  os << color.red << COLOR_DELIMITER
     << color.green << COLOR_DELIMITER
     << color.blue << COLOR_DELIMITER
     << color.alpha;
  return os;
}

template <typename T>
inline bool operator == ( const Color4<T>& left, const Color4<T>& right )
{
  return ( left.red == right.red ) &&
         ( left.green == right.green ) &&
         ( left.blue == right.blue ) &&
         ( left.alpha == right.alpha );
}

template <typename T>
inline bool operator != ( const Color4<T>& left, const Color4<T>& right )
{
  return ! ( left == right );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator + ( const Color4<T>& left, const Color4<T>& right )
{
  return Color4<T> ( static_cast<T> ( std::min ( left.red + right.red, 255 ) ),
                    static_cast<T> ( std::min ( left.green + right.green, 255 ) ),
                    static_cast<T> ( std::min ( left.blue + right.blue, 255 ) ),
                    static_cast<T> ( std::min ( left.alpha + right.alpha, 255 ) )
                  );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator ++ ( Color4<T>& left )
{
  return Color4<T> ( static_cast<T> ( left.red-- ),
                    static_cast<T> ( left.green-- ),
                    static_cast<T> ( left.blue-- ),
                    static_cast<T> ( left.alpha-- )
                );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator - ( const Color4<T>& left, const Color4<T>& right )
{
  return Color4<T> ( static_cast<T> ( std::min ( left.red - right.red, 255 ) ),
                    static_cast<T> ( std::min ( left.green - right.green, 255 ) ),
                    static_cast<T> ( std::min ( left.blue - right.blue, 255 ) ),
                    static_cast<T> ( std::min ( left.alpha - right.alpha, 255 ) )
                  );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator -- ( Color4<T>& left )
{
  return Color4<T> ( static_cast<T> ( left.red-- ),
                    static_cast<T> ( left.green-- ),
                    static_cast<T> ( left.blue-- ),
                    static_cast<T> ( left.alpha-- )
                  );
}

/// Values that exceed 255 are clamped to 255
template <typename T>
inline Color4<T> operator * ( const Color4<T>& left, const Color4<T>& right )
{
  return Color4<T> ( static_cast<T> ( left.red * right.red / 255 ),
                    static_cast<T> ( left.green * right.green / 255 ),
                    static_cast<T> ( left.blue * right.blue / 255 ),
                    static_cast<T> ( left.alpha * right.alpha / 255 )
                  );
}

template <typename T>
inline Color4<T>& operator += ( Color4<T>& left, const Color4<T>& right )
{
  return left = left + right;
}

template <typename T>
inline Color4<T>& operator -= ( Color4<T>& left, const Color4<T>& right )
{
  return left = left - right;
}

template <typename T>
inline Color4<T>& operator *= ( Color4<T>& left, const Color4<T>& right )
{
  return left = left * right;
}

typedef Color4<uint8> Color4u;
typedef Color4<float> Color4f;

} // namespace nom

/// Primary colors
#define NOM_COLOR4U_BLACK \
  nom::Color4u ( 0, 0, 0, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_WHITE \
  nom::Color4u ( 255, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_RED \
  nom::Color4u ( 255, 0, 0, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_GREEN \
  nom::Color4u ( 0, 255, 0, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_BLUE \
  nom::Color4u ( 0, 0, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_YELLOW \
  nom::Color4u ( 255, 255, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_MAGENTA \
  nom::Color4u ( 255, 0, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_CYAN \
  nom::Color4u ( 0, 255, 255, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_SILVER \
  nom::Color4u ( 192, 192, 192, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_PURPLE \
  nom::Color4u ( 128, 0, 128, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_ORANGE \
  nom::Color4u ( 255, 165, 0, nom::ALPHA_OPAQUE )

/// Additional colors
#define NOM_COLOR4U_LIGHT_GRAY \
  nom::Color4u ( 99, 99, 99, nom::ALPHA_OPAQUE )

#define NOM_COLOR4U_GRAY \
  nom::Color4u ( 67, 67, 67, nom::ALPHA_OPAQUE )

/// Light magenta color key
#define NOM_COLOR4U_PRIMARY_COLORKEY \
  nom::Color4u ( 110, 144, 190, nom::ALPHA_OPAQUE )

/// Sky blue color key
#define NOM_COLOR4U_SECONDARY_COLORKEY \
  nom::Color4u ( 223, 75, 255, nom::ALPHA_OPAQUE )

#endif // include guard defined
<|endoftext|>


<commit_before>/*
 * superviseddescent: A C++11 implementation of the supervised descent
 *                    optimisation method
 * File: rcr/adaptive_vlhog.hpp
 *
 * Copyright 2015 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef ADAPTIVE_VLHOG_HPP_
#define ADAPTIVE_VLHOG_HPP_

extern "C" {
	#include "hog.h" // From the VLFeat C library
}

#include "helpers.hpp"

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <vector>
#include <string>

namespace rcr {

struct HoGParam
{
	VlHogVariant vlhog_variant;
	int num_cells; int cell_size; int num_bins;
	float relative_patch_size; // the patch size we'd like in percent of the IED of the current image
	// note: alternatively, we could dynamically vary cell_size. Guess it works if the hog features are somehow normalised.

private:
	friend class cereal::access;
	/**
	 * Serialises this class using cereal.
	 *
	 * @param[in] ar The archive to serialise to (or to serialise from).
	 */
	template<class Archive>
	void serialize(Archive& ar)
	{
		ar(vlhog_variant, num_cells, cell_size, num_bins, relative_patch_size);
	}
};

/**
 * Function object that extracts HoG features at given 2D landmark locations
 * and returns them as a row vector.
 *
 * We wrap all the C-style memory allocations of the VLFeat library
 * in cv::Mat's.
 * Note: Any other library and features can of course be used.
 */
class HogTransform
{
public:
	/**
	 * Constructs a HoG transform with given images and parameters.
	 * The images are needed so the HoG features can be extracted from the images
	 * when the SupervisedDescentOptimiser calls this functor (the optimiser
	 * itself doesn't know and care about the images).
	 *
	 * Note: \p images can consist of only 1 image, when using the model for
	 * prediction on new images.
	 *
	 * Do not call with \p images that are temporaries!
	 *
	 * Note: Only VlHogVariantUoctti is tested.
	 *
	 * @param[in] images A vector of images used for training or testing.
	 * @param[in] vlHogVariant The VLFeat HoG variant.
	 * @param[in] numCells Number of HoG cells that should be constructed around each landmark.
	 * @param[in] cellSize Width of one HoG cell in pixels.
	 * @param[in] numBins Number of orientations of a HoG cell.
	 */
	HogTransform(const std::vector<cv::Mat>& images, std::vector<HoGParam> hog_params, std::vector<std::string> modelLandmarksList, std::vector<std::string> rightEyeIdentifiers, std::vector<std::string> leftEyeIdentifiers) : images(images), hog_params(hog_params), modelLandmarksList(modelLandmarksList), rightEyeIdentifiers(rightEyeIdentifiers), leftEyeIdentifiers(leftEyeIdentifiers)
	{
	};

	/**
	 * Uses the current parameters (the 2D landmark locations, in SDM
	 * terminology the \c x), and extracts HoG features at these positions.
	 * These HoG features are the new \c y values.
	 *
	 * The 2D landmark position estimates are given as a row vector
	 * [x_0, ..., x_n, y_0, ..., y_n].
	 *
	 * @param[in] parameters The current 2D landmark position estimate.
	 * @param[in] regressorLevel Not used in this example.
	 * @param[in] trainingIndex Gets supplied by the SupervisedDescent optimiser during training and testing, to know from which image to extract features.
	 * @return Returns the HoG features at the given 2D locations.
	 */
	cv::Mat operator()(cv::Mat parameters, size_t regressorLevel, int trainingIndex = 0)
	{
		assert(parameters.rows == 1);
		using cv::Mat;

		Mat grayImage;
		if (images[trainingIndex].channels() == 3) {
			cv::cvtColor(images[trainingIndex], grayImage, cv::COLOR_BGR2GRAY);
		}
		else {
			grayImage = images[trainingIndex];
		}

		// This is in pixels in the original image:
		int patch_width_half = std::round(hog_params[regressorLevel].relative_patch_size * get_ied(to_landmark_collection(parameters, modelLandmarksList), rightEyeIdentifiers, leftEyeIdentifiers) / 2); // Could use the formula of Zhenhua here, but we can use it in the app if desired

		// Ideally, these two values should be similar. If the second is much bigger, it's probably of not much use (we just upscale the images for nothing)
		//std::cout << "pw: " << patch_width_half * 2 << ", rs: " << hog_params[regressorLevel].num_cells * hog_params[regressorLevel].cell_size << std::endl;

		Mat hogDescriptors; // We'll get the dimensions later from vl_hog_get_*

		int numLandmarks = parameters.cols / 2;
		for (int i = 0; i < numLandmarks; ++i) {
			int x = cvRound(parameters.at<float>(i));
			int y = cvRound(parameters.at<float>(i + numLandmarks));

			Mat roiImg;
			if (x - patch_width_half < 0 || y - patch_width_half < 0 || x + patch_width_half >= grayImage.cols || y + patch_width_half >= grayImage.rows) {
				// The feature extraction location is too far near a border. We extend the
				// image (add a black canvas) and then extract from this larger image.
				int borderLeft = (x - patch_width_half) < 0 ? std::abs(x - patch_width_half) : 0; // x and y are patch-centers
				int borderTop = (y - patch_width_half) < 0 ? std::abs(y - patch_width_half) : 0;
				int borderRight = (x + patch_width_half) >= grayImage.cols ? std::abs(grayImage.cols - (x + patch_width_half)) : 0;
				int borderBottom = (y + patch_width_half) >= grayImage.rows ? std::abs(grayImage.rows - (y + patch_width_half)) : 0;
				Mat extendedImage = grayImage.clone();
				cv::copyMakeBorder(extendedImage, extendedImage, borderTop, borderBottom, borderLeft, borderRight, cv::BORDER_CONSTANT, cv::Scalar(0));
				cv::Rect roi((x - patch_width_half) + borderLeft, (y - patch_width_half) + borderTop, patch_width_half * 2, patch_width_half * 2); // Rect: x y w h. x and y are top-left corner.
				roiImg = extendedImage(roi).clone(); // clone because we need a continuous memory block
			}
			else {
				cv::Rect roi(x - patch_width_half, y - patch_width_half, patch_width_half * 2, patch_width_half * 2); // x y w h. Rect: x and y are top-left corner. Our x and y are center. Convert.
				roiImg = grayImage(roi).clone(); // clone because we need a continuous memory block
			}

			// This has to be the same for each image, so each image's HOG descriptor will have the same dimensions, independent of the image's resolution
			int fixed_roi_size = hog_params[regressorLevel].num_cells * hog_params[regressorLevel].cell_size;
			cv::resize(roiImg, roiImg, { fixed_roi_size, fixed_roi_size });

			roiImg.convertTo(roiImg, CV_32FC1); // vl_hog_put_image expects a float* (values 0.0f-255.0f)
			VlHog* hog = vl_hog_new(hog_params[regressorLevel].vlhog_variant, hog_params[regressorLevel].num_bins, false); // transposed (=col-major) = false
			vl_hog_put_image(hog, (float*)roiImg.data, roiImg.cols, roiImg.rows, 1, hog_params[regressorLevel].cell_size); // (the '1' is numChannels)
			int ww = static_cast<int>(vl_hog_get_width(hog)); // assert ww == hh == numCells
			int hh = static_cast<int>(vl_hog_get_height(hog));
			int dd = static_cast<int>(vl_hog_get_dimension(hog)); // assert ww=hogDim1, hh=hogDim2, dd=hogDim3
			Mat hogArray(1, ww*hh*dd, CV_32FC1); // safer & same result. Don't use C-style memory management.
			vl_hog_extract(hog, hogArray.ptr<float>(0));
			vl_hog_delete(hog);
			Mat hogDescriptor(hh*ww*dd, 1, CV_32FC1);
			// Stack the third dimensions of the HOG descriptor of this patch one after each other in a column-vector:
			for (int j = 0; j < dd; ++j) {
				Mat hogFeatures(hh, ww, CV_32FC1, hogArray.ptr<float>(0) + j*ww*hh); // Creates the same array as in Matlab. I might have to check this again if hh!=ww (non-square)
				hogFeatures = hogFeatures.t(); // necessary because the Matlab reshape() takes column-wise from the matrix while the OpenCV reshape() takes row-wise.
				hogFeatures = hogFeatures.reshape(0, hh*ww); // make it to a column-vector
				Mat currentDimSubMat = hogDescriptor.rowRange(j*ww*hh, j*ww*hh + ww*hh);
				hogFeatures.copyTo(currentDimSubMat);
			}
			hogDescriptor = hogDescriptor.t(); // now a row-vector
			hogDescriptors.push_back(hogDescriptor);
		}
		// concatenate all the descriptors for this sample vertically (into a row-vector):
		hogDescriptors = hogDescriptors.reshape(0, hogDescriptors.cols * numLandmarks).t();

		// add a bias row (affine part)
		Mat bias = Mat::ones(1, 1, CV_32FC1);
		cv::hconcat(hogDescriptors, bias, hogDescriptors);
		return hogDescriptors;
	};

private:
	const std::vector<cv::Mat>& images; // We store a reference so that each thread that gets spawned doesn't create a copy of this vector. An alternative might be to rethink the design and not store all images here.
	std::vector<HoGParam> hog_params;

	// For the IED normalisation / adaptive part:
	std::vector<std::string> modelLandmarksList;
	std::vector<std::string> rightEyeIdentifiers;
	std::vector<std::string> leftEyeIdentifiers;
};

} /* namespace rcr */

#endif /* ADAPTIVE_VLHOG_HPP_ */
<commit_msg>Fixed missing cereal header, updated documentation<commit_after>/*
 * superviseddescent: A C++11 implementation of the supervised descent
 *                    optimisation method
 * File: rcr/adaptive_vlhog.hpp
 *
 * Copyright 2015 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef ADAPTIVE_VLHOG_HPP_
#define ADAPTIVE_VLHOG_HPP_

extern "C" {
	#include "hog.h" // From the VLFeat C library
}

#include "helpers.hpp"

#include "cereal/access.hpp"

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <vector>
#include <string>

namespace rcr {

struct HoGParam
{
	VlHogVariant vlhog_variant;
	int num_cells; int cell_size; int num_bins;
	float relative_patch_size; // the patch size we'd like in percent of the IED of the current image
	// note: alternatively, we could dynamically vary cell_size. Guess it works if the hog features are somehow normalised.

private:
	friend class cereal::access;
	/**
	 * Serialises this class using cereal.
	 *
	 * @param[in] ar The archive to serialise to (or to serialise from).
	 */
	template<class Archive>
	void serialize(Archive& ar)
	{
		ar(vlhog_variant, num_cells, cell_size, num_bins, relative_patch_size);
	}
};

/**
 * Function object that extracts HoG features at given 2D landmark locations
 * and returns them as a row vector.
 *
 * We wrap all the C-style memory allocations of the VLFeat library
 * in cv::Mat's.
 * Note: Any other library and features can of course be used.
 */
class HogTransform
{
public:
	/**
	 * Constructs a HoG transform with given images and parameters.
	 * The images are needed so the HoG features can be extracted from the images
	 * when the SupervisedDescentOptimiser calls this functor (the optimiser
	 * itself doesn't know and care about the images).
	 *
	 * Note: \p images can consist of only 1 image, when using the model for
	 * prediction on new images.
	 *
	 * Do not call with \p images that are temporaries!
	 *
	 * Note: Only VlHogVariantUoctti is tested.
	 *
	 * @param[in] images A vector of images used for training or testing.
	 * @param[in] hog_params Parameters for the VLFeat HOG features.
	 * @param[in] modelLandmarksList Todo.
	 * @param[in] rightEyeIdentifiers Todo.
	 * @param[in] leftEyeIdentifiers Todo.
	 */
	HogTransform(const std::vector<cv::Mat>& images, std::vector<HoGParam> hog_params, std::vector<std::string> modelLandmarksList, std::vector<std::string> rightEyeIdentifiers, std::vector<std::string> leftEyeIdentifiers) : images(images), hog_params(hog_params), modelLandmarksList(modelLandmarksList), rightEyeIdentifiers(rightEyeIdentifiers), leftEyeIdentifiers(leftEyeIdentifiers)
	{
	};

	/**
	 * Uses the current parameters (the 2D landmark locations, in SDM
	 * terminology the \c x), and extracts HoG features at these positions.
	 * These HoG features are the new \c y values.
	 *
	 * The 2D landmark position estimates are given as a row vector
	 * [x_0, ..., x_n, y_0, ..., y_n].
	 *
	 * @param[in] parameters The current 2D landmark position estimate.
	 * @param[in] regressorLevel Not used in this example.
	 * @param[in] trainingIndex Gets supplied by the SupervisedDescent optimiser during training and testing, to know from which image to extract features.
	 * @return Returns the HoG features at the given 2D locations.
	 */
	cv::Mat operator()(cv::Mat parameters, size_t regressorLevel, int trainingIndex = 0)
	{
		assert(parameters.rows == 1);
		using cv::Mat;

		Mat grayImage;
		if (images[trainingIndex].channels() == 3) {
			cv::cvtColor(images[trainingIndex], grayImage, cv::COLOR_BGR2GRAY);
		}
		else {
			grayImage = images[trainingIndex];
		}

		// This is in pixels in the original image:
		int patch_width_half = std::round(hog_params[regressorLevel].relative_patch_size * get_ied(to_landmark_collection(parameters, modelLandmarksList), rightEyeIdentifiers, leftEyeIdentifiers) / 2); // Could use the formula of Zhenhua here, but we can use it in the app if desired

		// Ideally, these two values should be similar. If the second is much bigger, it's probably of not much use (we just upscale the images for nothing)
		//std::cout << "pw: " << patch_width_half * 2 << ", rs: " << hog_params[regressorLevel].num_cells * hog_params[regressorLevel].cell_size << std::endl;

		Mat hogDescriptors; // We'll get the dimensions later from vl_hog_get_*

		int numLandmarks = parameters.cols / 2;
		for (int i = 0; i < numLandmarks; ++i) {
			int x = cvRound(parameters.at<float>(i));
			int y = cvRound(parameters.at<float>(i + numLandmarks));

			Mat roiImg;
			if (x - patch_width_half < 0 || y - patch_width_half < 0 || x + patch_width_half >= grayImage.cols || y + patch_width_half >= grayImage.rows) {
				// The feature extraction location is too far near a border. We extend the
				// image (add a black canvas) and then extract from this larger image.
				int borderLeft = (x - patch_width_half) < 0 ? std::abs(x - patch_width_half) : 0; // x and y are patch-centers
				int borderTop = (y - patch_width_half) < 0 ? std::abs(y - patch_width_half) : 0;
				int borderRight = (x + patch_width_half) >= grayImage.cols ? std::abs(grayImage.cols - (x + patch_width_half)) : 0;
				int borderBottom = (y + patch_width_half) >= grayImage.rows ? std::abs(grayImage.rows - (y + patch_width_half)) : 0;
				Mat extendedImage = grayImage.clone();
				cv::copyMakeBorder(extendedImage, extendedImage, borderTop, borderBottom, borderLeft, borderRight, cv::BORDER_CONSTANT, cv::Scalar(0));
				cv::Rect roi((x - patch_width_half) + borderLeft, (y - patch_width_half) + borderTop, patch_width_half * 2, patch_width_half * 2); // Rect: x y w h. x and y are top-left corner.
				roiImg = extendedImage(roi).clone(); // clone because we need a continuous memory block
			}
			else {
				cv::Rect roi(x - patch_width_half, y - patch_width_half, patch_width_half * 2, patch_width_half * 2); // x y w h. Rect: x and y are top-left corner. Our x and y are center. Convert.
				roiImg = grayImage(roi).clone(); // clone because we need a continuous memory block
			}

			// This has to be the same for each image, so each image's HOG descriptor will have the same dimensions, independent of the image's resolution
			int fixed_roi_size = hog_params[regressorLevel].num_cells * hog_params[regressorLevel].cell_size;
			cv::resize(roiImg, roiImg, { fixed_roi_size, fixed_roi_size });

			roiImg.convertTo(roiImg, CV_32FC1); // vl_hog_put_image expects a float* (values 0.0f-255.0f)
			VlHog* hog = vl_hog_new(hog_params[regressorLevel].vlhog_variant, hog_params[regressorLevel].num_bins, false); // transposed (=col-major) = false
			vl_hog_put_image(hog, (float*)roiImg.data, roiImg.cols, roiImg.rows, 1, hog_params[regressorLevel].cell_size); // (the '1' is numChannels)
			int ww = static_cast<int>(vl_hog_get_width(hog)); // assert ww == hh == numCells
			int hh = static_cast<int>(vl_hog_get_height(hog));
			int dd = static_cast<int>(vl_hog_get_dimension(hog)); // assert ww=hogDim1, hh=hogDim2, dd=hogDim3
			Mat hogArray(1, ww*hh*dd, CV_32FC1); // safer & same result. Don't use C-style memory management.
			vl_hog_extract(hog, hogArray.ptr<float>(0));
			vl_hog_delete(hog);
			Mat hogDescriptor(hh*ww*dd, 1, CV_32FC1);
			// Stack the third dimensions of the HOG descriptor of this patch one after each other in a column-vector:
			for (int j = 0; j < dd; ++j) {
				Mat hogFeatures(hh, ww, CV_32FC1, hogArray.ptr<float>(0) + j*ww*hh); // Creates the same array as in Matlab. I might have to check this again if hh!=ww (non-square)
				hogFeatures = hogFeatures.t(); // necessary because the Matlab reshape() takes column-wise from the matrix while the OpenCV reshape() takes row-wise.
				hogFeatures = hogFeatures.reshape(0, hh*ww); // make it to a column-vector
				Mat currentDimSubMat = hogDescriptor.rowRange(j*ww*hh, j*ww*hh + ww*hh);
				hogFeatures.copyTo(currentDimSubMat);
			}
			hogDescriptor = hogDescriptor.t(); // now a row-vector
			hogDescriptors.push_back(hogDescriptor);
		}
		// concatenate all the descriptors for this sample vertically (into a row-vector):
		hogDescriptors = hogDescriptors.reshape(0, hogDescriptors.cols * numLandmarks).t();

		// add a bias row (affine part)
		Mat bias = Mat::ones(1, 1, CV_32FC1);
		cv::hconcat(hogDescriptors, bias, hogDescriptors);
		return hogDescriptors;
	};

private:
	const std::vector<cv::Mat>& images; // We store a reference so that each thread that gets spawned doesn't create a copy of this vector. An alternative might be to rethink the design and not store all images here.
	std::vector<HoGParam> hog_params;

	// For the IED normalisation / adaptive part:
	std::vector<std::string> modelLandmarksList;
	std::vector<std::string> rightEyeIdentifiers;
	std::vector<std::string> leftEyeIdentifiers;
};

} /* namespace rcr */

#endif /* ADAPTIVE_VLHOG_HPP_ */
<|endoftext|>


<commit_before>#ifndef DUNE_DETAILED_DISCRETIZATIONS_MAPPER_INTERFACE_HH
#define DUNE_DETAILED_DISCRETIZATIONS_MAPPER_INTERFACE_HH

#include <dune/common/bartonnackmanifcheck.hh>
#include <dune/common/dynvector.hh>

namespace Dune {
namespace Detailed {
namespace Discretizations {

template< class Traits >
class MapperInterface
{
public:
  typedef typename Traits::derived_type derived_type;

  typedef typename Traits::BackendType  BackendType;

  const BackendType& backend() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().backend());
    return asImp().backend();
  }

  size_t size() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().size());
    return asImp().size();
  }

  size_t maxNumDofs() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().maxNumDofs());
    return asImp().maxNumDofs();
  }

  template< class EntityType >
  size_t numDofs(const EntityType& entity) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().numDofs(entity));
    return asImp().numDofs(entity);
  }

  template< class EntityType >
  void mapToGlobal(const EntityType& entity, Dune::DynamicVector< size_t >& globalIndices) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().mapToGlobal(entity, globalIndices));
    asImp().mapToGlobal(entity, globalIndices);
  }

  template< class EntityType >
  size_t mapToGlobal(const EntityType& entity, const size_t& localIndex) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().mapToGlobal(entity, localIndex));
    return asImp().mapToGlobal(entity, localIndex);
  }

  derived_type& asImp()
  {
    return static_cast< derived_type& >(*this);
  }

  const derived_type& asImp() const
  {
    return static_cast< const derived_type& >(*this);
  }
}; // class MapperInterface

} // namespace Discretizations
} // namespace Detailed
} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_MAPPER_INTERFACE_HH
<commit_msg>[mapper.interface] renamed mapToGlobal() -> globalIndices()<commit_after>#ifndef DUNE_DETAILED_DISCRETIZATIONS_MAPPER_INTERFACE_HH
#define DUNE_DETAILED_DISCRETIZATIONS_MAPPER_INTERFACE_HH

#include <dune/common/bartonnackmanifcheck.hh>
#include <dune/common/dynvector.hh>

namespace Dune {
namespace Detailed {
namespace Discretizations {

template< class Traits >
class MapperInterface
{
public:
  typedef typename Traits::derived_type derived_type;

  typedef typename Traits::BackendType  BackendType;

  const BackendType& backend() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().backend());
    return asImp().backend();
  }

  size_t size() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().size());
    return asImp().size();
  }

  size_t maxNumDofs() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().maxNumDofs());
    return asImp().maxNumDofs();
  }

  template< class EntityType >
  size_t numDofs(const EntityType& entity) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().numDofs(entity));
    return asImp().numDofs(entity);
  }

  template< class EntityType >
  void globalIndices(const EntityType& entity, Dune::DynamicVector< size_t >& ret) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().globalIndices(entity, ret));
    asImp().globalIndices(entity, ret);
  }

  template< class EntityType >
  size_t mapToGlobal(const EntityType& entity, const size_t& localIndex) const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().mapToGlobal(entity, localIndex));
    return asImp().mapToGlobal(entity, localIndex);
  }

  derived_type& asImp()
  {
    return static_cast< derived_type& >(*this);
  }

  const derived_type& asImp() const
  {
    return static_cast< const derived_type& >(*this);
  }
}; // class MapperInterface

} // namespace Discretizations
} // namespace Detailed
} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_MAPPER_INTERFACE_HH
<|endoftext|>


<commit_before>#ifndef _TOOLBOX_CPP_FORMAT_HPP_
#define _TOOLBOX_CPP_FORMAT_HPP_

#include <toolbox/container/stack.hpp>
#include <toolbox/cpp/span.hpp>

namespace toolbox
{

namespace format {
namespace detail {
struct flags {
    bool hex = 0;
};
} // namespace detail
template<typename Output, typename T>
void format(Output &out, detail::flags flags, T number)
{
    // TODO: may be removed when we fix stack size
    static_assert(sizeof(number) <= 4, "does not support integer types > 4 bytes");

    if (flags.hex == false) {
        // TODO: allocate stack based on max dec representation
        // of type T, for now we assume 32 bit integer which
        // may have up to 10 digits in dec representation
        toolbox::stack<char, 10> stack;

        while (number != 0) {
            char c = number % 10;
            stack.emplace_back('0' + c);
            number = number / 10;
        }

        while (stack.size()) {
            out.put(stack.back());
            stack.pop_back();
        }
    } else if (flags.hex == true) {
        static char lt[] = {
            '0', '1', '2', '3', '4',
            '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E',
            'F'
        };

        constexpr auto hexSize = sizeof(T) * 2;
        for (unsigned i = 0; i < hexSize; i ++) {
            out.put(
                lt[(number >> (hexSize-1-i)*4) & 0xf]
            );
        }
    }
}

template<typename Output>
void print(Output &out, const char *fmt)
{
    while (*fmt) {
        out.put(*fmt);
        fmt ++;
    }
}

namespace detail
{
template<template<typename> class M, class T>
struct modifier
{
    modifier(const T& value)
        : value (value)
    {}

    using type = T;
    const T& value;
};
}

template<template <typename> class M, class T>
auto modifier(const T& value)
{
    return detail::modifier<M, T>(value);
}

template<class Out>
struct Quote
{
    Quote(Out &out)
        : out (out)
    {
        out.put('"');
    }

    ~Quote()
    {
        out.put('"');
    }

    Out &out;
};

template<typename Output, template<typename> class M, typename T>
void format(Output &out, detail::flags flags, const detail::modifier<M, T> &m)
{
    M<Output> mod(out);
    format(out, flags, m.value);
}

template<typename Output, typename Next>
void format_argument(Output &out, span<const char> fmt, const Next &next)
{
    detail::flags flags;

    for (auto c : fmt)
    {
        if (c == 'x') {
            flags.hex = true;
        }
    }

    format(out, flags, next);
}

template<typename Output, typename Next, typename... Args>
void print(Output &out, const char *fmt, const Next &next, const Args&... args)
{
    bool format = false;
    const char *fmtBegin = nullptr;
    detail::flags flags;

    while (*fmt) {
        if (format) {
            if (*fmt == '}') {
                format_argument(out, span<const char>{fmtBegin, fmt}, next);
                print(out, fmt + 1, args...);
                return;
            }
        } else {
            if (*fmt != '{') {
                out.put(*fmt);
            } else {
                format = true;
                fmtBegin = fmt + 1;
            }
        }

        fmt ++;
    }
}

} // namespace format
} // namespace toolbox

#endif // _TOOLBOX_CPP_FORMAT_HPP_
<commit_msg>remove unused local variable<commit_after>#ifndef _TOOLBOX_CPP_FORMAT_HPP_
#define _TOOLBOX_CPP_FORMAT_HPP_

#include <toolbox/container/stack.hpp>
#include <toolbox/cpp/span.hpp>

namespace toolbox
{

namespace format {
namespace detail {
struct flags {
    bool hex = 0;
};
} // namespace detail
template<typename Output, typename T>
void format(Output &out, detail::flags flags, T number)
{
    // TODO: may be removed when we fix stack size
    static_assert(sizeof(number) <= 4, "does not support integer types > 4 bytes");

    if (flags.hex == false) {
        // TODO: allocate stack based on max dec representation
        // of type T, for now we assume 32 bit integer which
        // may have up to 10 digits in dec representation
        toolbox::stack<char, 10> stack;

        while (number != 0) {
            char c = number % 10;
            stack.emplace_back('0' + c);
            number = number / 10;
        }

        while (stack.size()) {
            out.put(stack.back());
            stack.pop_back();
        }
    } else if (flags.hex == true) {
        static char lt[] = {
            '0', '1', '2', '3', '4',
            '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E',
            'F'
        };

        constexpr auto hexSize = sizeof(T) * 2;
        for (unsigned i = 0; i < hexSize; i ++) {
            out.put(
                lt[(number >> (hexSize-1-i)*4) & 0xf]
            );
        }
    }
}

template<typename Output>
void print(Output &out, const char *fmt)
{
    while (*fmt) {
        out.put(*fmt);
        fmt ++;
    }
}

namespace detail
{
template<template<typename> class M, class T>
struct modifier
{
    modifier(const T& value)
        : value (value)
    {}

    using type = T;
    const T& value;
};
}

template<template <typename> class M, class T>
auto modifier(const T& value)
{
    return detail::modifier<M, T>(value);
}

template<class Out>
struct Quote
{
    Quote(Out &out)
        : out (out)
    {
        out.put('"');
    }

    ~Quote()
    {
        out.put('"');
    }

    Out &out;
};

template<typename Output, template<typename> class M, typename T>
void format(Output &out, detail::flags flags, const detail::modifier<M, T> &m)
{
    M<Output> mod(out);
    format(out, flags, m.value);
}

template<typename Output, typename Next>
void format_argument(Output &out, span<const char> fmt, const Next &next)
{
    detail::flags flags;

    for (auto c : fmt)
    {
        if (c == 'x') {
            flags.hex = true;
        }
    }

    format(out, flags, next);
}

template<typename Output, typename Next, typename... Args>
void print(Output &out, const char *fmt, const Next &next, const Args&... args)
{
    bool format = false;
    const char *fmtBegin = nullptr;

    while (*fmt) {
        if (format) {
            if (*fmt == '}') {
                format_argument(out, span<const char>{fmtBegin, fmt}, next);
                print(out, fmt + 1, args...);
                return;
            }
        } else {
            if (*fmt != '{') {
                out.put(*fmt);
            } else {
                format = true;
                fmtBegin = fmt + 1;
            }
        }

        fmt ++;
    }
}

} // namespace format
} // namespace toolbox

#endif // _TOOLBOX_CPP_FORMAT_HPP_
<|endoftext|>


<commit_before>#include <config.h>
#include <assert.h>
#include <dune/common/exceptions.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/stuff/common/ranges.hh>
#include <dune/stuff/functions/femadapter.hh>
#include <dune/stuff/common/profiler.hh>
#include <dune/fem/misc/threads/domainthreaditerator.hh>
#include <memory>

#include <dune/stuff/fem/functions/integrals.hh>
#include <dune/stuff/functions/femadapter.hh>
#include <dune/multiscale/common/traits.hh>
#include <dune/multiscale/tools/misc.hh>
#include <dune/multiscale/common/dirichletconstraints.hh>
#include <dune/multiscale/msfem/localproblems/subgrid-list.hh>
#include <dune/multiscale/msfem/localproblems/localsolutionmanager.hh>

#include "righthandside_assembler.hh"

void Dune::Multiscale::RightHandSideAssembler::assemble_msfem(
    const CommonTraits::DiscreteFunctionSpaceType& coarse_space,
    const Dune::Multiscale::CommonTraits::FirstSourceType& f, DMM::LocalGridList& subgrid_list,
    Dune::Multiscale::CommonTraits::DiscreteFunctionType& rhsVector) {

  // cache grid variable
  bool isSimplexGrid = DSG::is_simplex_grid(coarse_space);

  static constexpr int dimension = CommonTraits::GridType::dimension;
  DSC_PROFILER.startTiming("msfem.assembleRHS");
  const auto& diffusion = *Problem::getDiffusion();
  const auto& neumannData = *Problem::getNeumannData();

  rhsVector.clear();
  RangeType f_x;
  Fem::DomainDecomposedIteratorStorage<CommonTraits::GridPartType> threadIterators(rhsVector.space().gridPart());

#ifdef _OPENMP
#pragma omp parallel
#endif
  {
    for (const auto& coarse_grid_entity : threadIterators) {
      const auto& coarseGeometry = coarse_grid_entity.geometry();
      auto rhsLocalFunction = rhsVector.localFunction(coarse_grid_entity);
      const auto numLocalBaseFunctions = rhsLocalFunction.numDofs();
      const auto& coarseBaseSet = coarse_space.basisFunctionSet(coarse_grid_entity);

      // --------- add corrector contribution of right hand side --------------------------
      // Load local solutions
      MsFEM::LocalSolutionManager localSolutionManager(coarse_space, coarse_grid_entity, subgrid_list);
      localSolutionManager.load();
      auto& localSolutions = localSolutionManager.getLocalSolutions();
      assert(localSolutions.size() > 0);
      MsFEM::MsFEMTraits::LocalGridDiscreteFunctionType dirichletExtension("Dirichlet Extension",
                                                                           localSolutionManager.space());
      dirichletExtension.clear();
      Dune::Multiscale::copyDirichletValues(rhsVector.space(), dirichletExtension);

      // iterator for the micro grid ( grid for the reference element T_0 )
      const auto& subGrid = subgrid_list.getSubGrid(coarse_grid_entity);
      auto view = subGrid.leafGridView();
      for (const auto& localEntity : DSC::viewRange(view)) {
        if (subgrid_list.covers(coarse_grid_entity, localEntity)) {
          // higher order quadrature, since A^{\epsilon} is highly variable
          const auto localQuadrature = DSFe::make_quadrature(localEntity, localSolutionManager.space());
          auto dirichletExtensionLF = dirichletExtension.localFunction(localEntity);

          // evaluate all local solutions and their jacobians in all quadrature points
          std::vector<std::vector<RangeType>> allLocalSolutionEvaluations(
              localSolutions.size(), std::vector<RangeType>(localQuadrature.nop(), 0.0));
          std::vector<std::vector<JacobianRangeType>> allLocalSolutionJacobians(
              localSolutions.size(), std::vector<JacobianRangeType>(localQuadrature.nop(), JacobianRangeType(0.0)));
          for (auto lsNum : DSC::valueRange(localSolutions.size())) {
            auto localFunction = localSolutions[lsNum]->localFunction(localEntity);
            // this evaluates the local solutions in all quadrature points...
            localFunction.evaluateQuadrature(localQuadrature, allLocalSolutionEvaluations[lsNum]);
            // while this automatically evaluates their jacobians.
            localFunction.evaluateQuadrature(localQuadrature, allLocalSolutionJacobians[lsNum]);

            // assemble intersection-part
            const auto& subGridPart = localSolutionManager.grid_part();
            for (const auto& intersection : DSC::intersectionRange(subGridPart.grid().leafGridView(), localEntity)) {
              if (DMP::is_neumann(intersection)) {
                const int orderOfIntegrand =
                    (CommonTraits::polynomial_order - 1) + 2 * (CommonTraits::polynomial_order + 1);
                const int quadOrder = std::ceil((orderOfIntegrand + 1) / 2);
                const auto faceQuad = DSFe::make_quadrature(intersection, localSolutions[lsNum]->space(), quadOrder);
                RangeType neumannValue(0.0);
                const auto numQuadPoints = faceQuad.nop();
                // loop over all quadrature points

                std::vector<RangeType> phi_x_vec(numLocalBaseFunctions);
                std::vector<RangeType> localSolutionOnFace(numLocalBaseFunctions);
                localFunction.evaluateQuadrature(faceQuad, localSolutionOnFace);

                for (unsigned int iqP = 0; iqP < numQuadPoints; ++iqP) {
                  // get local coordinate of quadrature point
                  const auto& xLocal = faceQuad.localPoint(iqP);
                  const auto& faceGeometry = intersection.geometry();
                  const auto& xGlobal = faceGeometry.global(xLocal);
                  const auto& xInCoarseLocal = coarse_grid_entity.geometry().local(xGlobal);
                  const double factor = faceGeometry.integrationElement(xLocal) * faceQuad.weight(iqP);

                  neumannData.evaluate(xGlobal, neumannValue);
                  coarseBaseSet.evaluateAll(xInCoarseLocal, phi_x_vec);
                  for (auto i : DSC::valueRange(numLocalBaseFunctions)) {
                    assert((long long)i < (long long)phi_x_vec.size());
                    assert(iqP < localSolutionOnFace.size());
                    rhsLocalFunction[i] += factor * (neumannValue * (phi_x_vec[i] + localSolutionOnFace[iqP]));
                  }
                }
              }
            }
          }

          // assemble element-part
          const auto& localGeometry = localEntity.geometry();
          for (size_t qP = 0; qP < localQuadrature.nop(); ++qP) {
            // local (barycentric) coordinates (with respect to entity)
            const auto& quadPoint = localQuadrature.point(qP);
            const auto quadPointGlobal = localGeometry.global(quadPoint);

            const double quadWeight = localQuadrature.weight(qP) * localGeometry.integrationElement(quadPoint);

            // evaluate gradient of basis function
            const auto quadPointLocalInCoarse = coarseGeometry.local(quadPointGlobal);
            std::vector<RangeType> coarseBaseEvals(numLocalBaseFunctions);
            std::vector<JacobianRangeType> coarseBaseJacs(numLocalBaseFunctions);
            coarseBaseSet.evaluateAll(quadPointLocalInCoarse, coarseBaseEvals);
            coarseBaseSet.jacobianAll(quadPointLocalInCoarse, coarseBaseJacs);

            for (int coarseBF = 0; coarseBF < numLocalBaseFunctions; ++coarseBF) {
              JacobianRangeType diffusive_flux(0.0);

              JacobianRangeType reconstructionGradPhi(coarseBaseJacs[coarseBF]);
              RangeType reconstructionPhi(coarseBaseEvals[coarseBF]);

              if (isSimplexGrid) {
                assert(localSolutions.size() == dimension + localSolutionManager.numBoundaryCorrectors());
                for (const auto& i : DSC::valueRange(dimension))
                  reconstructionPhi += coarseBaseJacs[coarseBF][0][i] * allLocalSolutionEvaluations[i][qP];
                //! @todo add the dirichlet and neumann-correctors!
              } else {
                assert(localSolutions.size() == numLocalBaseFunctions + localSolutionManager.numBoundaryCorrectors());
                // local corrector for coarse base func
                reconstructionPhi += allLocalSolutionEvaluations[coarseBF][qP];
                // element part of boundary conditions
                JacobianRangeType directionOfFlux(0.0);
                //! @attention At this point we assume, that the quadrature points on the subgrid and hostgrid
                //! are the same (dirichletExtensionLF is a localfunction on the hostgrid, quadPoint stems from
                //! a quadrature on the subgrid)!!
                dirichletExtensionLF.jacobian(quadPoint, directionOfFlux);
                // add dirichlet-corrector
                directionOfFlux += allLocalSolutionJacobians[numLocalBaseFunctions + 1][qP];
                // subtract neumann-corrector
                directionOfFlux -= allLocalSolutionJacobians[numLocalBaseFunctions][qP];

                diffusion.diffusiveFlux(quadPointGlobal, directionOfFlux, diffusive_flux);
                reconstructionGradPhi += allLocalSolutionJacobians[coarseBF][qP];
              }
              f.evaluate(quadPointGlobal, f_x);

              rhsLocalFunction[coarseBF] += quadWeight * (f_x * reconstructionPhi);
              rhsLocalFunction[coarseBF] -= quadWeight * (diffusive_flux[0] * reconstructionGradPhi[0]);
            }
          }
        }
      }
    } // for
  }   // omp region

  // set dirichlet dofs to zero
  Dune::Multiscale::getConstraintsCoarse(rhsVector.space()).setValue(0.0, rhsVector);
  rhsVector.communicate();
  DSC_LOG_INFO << "Time to assemble and communicate MsFEM rhs: " << DSC_PROFILER.stopTiming("msfem.assembleRHS") << "ms"
               << std::endl;
}
<commit_msg>fixed bug where non-zero neumann values were not working<commit_after>#include <config.h>
#include <assert.h>
#include <dune/common/exceptions.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/stuff/common/ranges.hh>
#include <dune/stuff/functions/femadapter.hh>
#include <dune/stuff/common/profiler.hh>
#include <dune/fem/misc/threads/domainthreaditerator.hh>
#include <memory>

#include <dune/stuff/fem/functions/integrals.hh>
#include <dune/stuff/functions/femadapter.hh>
#include <dune/multiscale/common/traits.hh>
#include <dune/multiscale/tools/misc.hh>
#include <dune/multiscale/common/dirichletconstraints.hh>
#include <dune/multiscale/msfem/localproblems/subgrid-list.hh>
#include <dune/multiscale/msfem/localproblems/localsolutionmanager.hh>

#include "righthandside_assembler.hh"

void Dune::Multiscale::RightHandSideAssembler::assemble_msfem(
    const CommonTraits::DiscreteFunctionSpaceType& coarse_space,
    const Dune::Multiscale::CommonTraits::FirstSourceType& f, DMM::LocalGridList& subgrid_list,
    Dune::Multiscale::CommonTraits::DiscreteFunctionType& rhsVector) {

  // cache grid variable
  bool isSimplexGrid = DSG::is_simplex_grid(coarse_space);

  static constexpr int dimension = CommonTraits::GridType::dimension;
  DSC_PROFILER.startTiming("msfem.assembleRHS");
  const auto& diffusion = *Problem::getDiffusion();
  const auto& neumannData = *Problem::getNeumannData();

  rhsVector.clear();
  RangeType f_x;
  Fem::DomainDecomposedIteratorStorage<CommonTraits::GridPartType> threadIterators(rhsVector.space().gridPart());

#ifdef _OPENMP
#pragma omp parallel
#endif
  {
    for (const auto& coarse_grid_entity : threadIterators) {
      const auto& coarseGeometry = coarse_grid_entity.geometry();
      auto rhsLocalFunction = rhsVector.localFunction(coarse_grid_entity);
      const auto numLocalBaseFunctions = rhsLocalFunction.numDofs();
      const auto& coarseBaseSet = coarse_space.basisFunctionSet(coarse_grid_entity);

      // --------- add corrector contribution of right hand side --------------------------
      // Load local solutions
      MsFEM::LocalSolutionManager localSolutionManager(coarse_space, coarse_grid_entity, subgrid_list);
      localSolutionManager.load();
      auto& localSolutions = localSolutionManager.getLocalSolutions();
      assert(localSolutions.size() > 0);
      MsFEM::MsFEMTraits::LocalGridDiscreteFunctionType dirichletExtension("Dirichlet Extension",
                                                                           localSolutionManager.space());
      dirichletExtension.clear();
      Dune::Multiscale::copyDirichletValues(rhsVector.space(), dirichletExtension);

      // iterator for the micro grid ( grid for the reference element T_0 )
      const auto& subGrid = subgrid_list.getSubGrid(coarse_grid_entity);
      auto view = subGrid.leafGridView();
      for (const auto& localEntity : DSC::viewRange(view)) {
        if (subgrid_list.covers(coarse_grid_entity, localEntity)) {
          // higher order quadrature, since A^{\epsilon} is highly variable
          const auto localQuadrature = DSFe::make_quadrature(localEntity, localSolutionManager.space());
          auto dirichletExtensionLF = dirichletExtension.localFunction(localEntity);

          // evaluate all local solutions and their jacobians in all quadrature points
          std::vector<std::vector<RangeType>> allLocalSolutionEvaluations(
              localSolutions.size(), std::vector<RangeType>(localQuadrature.nop(), 0.0));
          std::vector<std::vector<JacobianRangeType>> allLocalSolutionJacobians(
              localSolutions.size(), std::vector<JacobianRangeType>(localQuadrature.nop(), JacobianRangeType(0.0)));
          // add contributions for all inner correctors
          for (auto lsNum : DSC::valueRange(numLocalBaseFunctions)) {
            auto localFunction = localSolutions[lsNum]->localFunction(localEntity);
            // this evaluates the local solutions in all quadrature points...
            localFunction.evaluateQuadrature(localQuadrature, allLocalSolutionEvaluations[lsNum]);
            // while this automatically evaluates their jacobians.
            localFunction.evaluateQuadrature(localQuadrature, allLocalSolutionJacobians[lsNum]);

            // assemble intersection-part
            const auto& subGridPart = localSolutionManager.grid_part();
            for (const auto& intersection : DSC::intersectionRange(subGridPart.grid().leafGridView(), localEntity)) {
              if (DMP::is_neumann(intersection)) {
                const int orderOfIntegrand =
                    (CommonTraits::polynomial_order - 1) + 2 * (CommonTraits::polynomial_order + 1);
                const int quadOrder = std::ceil((orderOfIntegrand + 1) / 2);
                const auto faceQuad = DSFe::make_quadrature(intersection, localSolutions[lsNum]->space(), quadOrder);
                RangeType neumannValue(0.0);
                const auto numQuadPoints = faceQuad.nop();
                // loop over all quadrature points

                std::vector<RangeType> phi_x_vec(numLocalBaseFunctions);
                std::vector<RangeType> localSolutionOnFace(numLocalBaseFunctions);
                localFunction.evaluateQuadrature(faceQuad, localSolutionOnFace);

                for (unsigned int iqP = 0; iqP < numQuadPoints; ++iqP) {
                  // get local coordinate of quadrature point
                  const auto& xLocal = faceQuad.localPoint(iqP);
                  const auto& faceGeometry = intersection.geometry();
                  const auto& xGlobal = faceGeometry.global(xLocal);
                  const auto& xInCoarseLocal = coarse_grid_entity.geometry().local(xGlobal);
                  const double factor = faceGeometry.integrationElement(xLocal) * faceQuad.weight(iqP);

                  neumannData.evaluate(xGlobal, neumannValue);
                  coarseBaseSet.evaluateAll(xInCoarseLocal, phi_x_vec);
                  assert((long long)lsNum < (long long)phi_x_vec.size());
                  assert(iqP < localSolutionOnFace.size());
                  rhsLocalFunction[lsNum] -= factor * (neumannValue * (phi_x_vec[lsNum] + localSolutionOnFace[iqP]));
                }
              }
            }
          }

          // assemble element-part
          const auto& localGeometry = localEntity.geometry();
          for (size_t qP = 0; qP < localQuadrature.nop(); ++qP) {
            // local (barycentric) coordinates (with respect to entity)
            const auto& quadPoint = localQuadrature.point(qP);
            const auto quadPointGlobal = localGeometry.global(quadPoint);

            const double quadWeight = localQuadrature.weight(qP) * localGeometry.integrationElement(quadPoint);

            // evaluate gradient of basis function
            const auto quadPointLocalInCoarse = coarseGeometry.local(quadPointGlobal);
            std::vector<RangeType> coarseBaseEvals(numLocalBaseFunctions);
            std::vector<JacobianRangeType> coarseBaseJacs(numLocalBaseFunctions);
            coarseBaseSet.evaluateAll(quadPointLocalInCoarse, coarseBaseEvals);
            coarseBaseSet.jacobianAll(quadPointLocalInCoarse, coarseBaseJacs);

            for (int coarseBF = 0; coarseBF < numLocalBaseFunctions; ++coarseBF) {
              JacobianRangeType diffusive_flux(0.0);

              JacobianRangeType reconstructionGradPhi(coarseBaseJacs[coarseBF]);
              RangeType reconstructionPhi(coarseBaseEvals[coarseBF]);

              if (isSimplexGrid) {
                assert(localSolutions.size() == dimension + localSolutionManager.numBoundaryCorrectors());
                for (const auto& i : DSC::valueRange(dimension))
                  reconstructionPhi += coarseBaseJacs[coarseBF][0][i] * allLocalSolutionEvaluations[i][qP];
                //! @todo add the dirichlet and neumann-correctors!
              } else {
                assert(localSolutions.size() == numLocalBaseFunctions + localSolutionManager.numBoundaryCorrectors());
                // local corrector for coarse base func
                reconstructionPhi += allLocalSolutionEvaluations[coarseBF][qP];
                // element part of boundary conditions
                JacobianRangeType directionOfFlux(0.0);
                //! @attention At this point we assume, that the quadrature points on the subgrid and hostgrid
                //! are the same (dirichletExtensionLF is a localfunction on the hostgrid, quadPoint stems from
                //! a quadrature on the subgrid)!!
                dirichletExtensionLF.jacobian(quadPoint, directionOfFlux);
                // add dirichlet-corrector
                directionOfFlux += allLocalSolutionJacobians[numLocalBaseFunctions + 1][qP];
                // subtract neumann-corrector
                directionOfFlux -= allLocalSolutionJacobians[numLocalBaseFunctions][qP];

                diffusion.diffusiveFlux(quadPointGlobal, directionOfFlux, diffusive_flux);
                reconstructionGradPhi += allLocalSolutionJacobians[coarseBF][qP];
              }
              f.evaluate(quadPointGlobal, f_x);

              rhsLocalFunction[coarseBF] += quadWeight * (f_x * reconstructionPhi);
              rhsLocalFunction[coarseBF] -= quadWeight * (diffusive_flux[0] * reconstructionGradPhi[0]);
            }
          }
        }
      }
    } // for
  }   // omp region

  // set dirichlet dofs to zero
  Dune::Multiscale::getConstraintsCoarse(rhsVector.space()).setValue(0.0, rhsVector);
  rhsVector.communicate();
  DSC_LOG_INFO << "Time to assemble and communicate MsFEM rhs: " << DSC_PROFILER.stopTiming("msfem.assembleRHS") << "ms"
               << std::endl;
}
<|endoftext|>


<commit_before>#ifndef UINT_T_HPP
#define UINT_T_HPP

#include <cstdint>
/** class for storing integers of arbitrary bits.
 * Useful values are 40,48, and 56.
 * Standard value is 40 bits since we can store values up to 1TiB and
 * address values up to 1TB with 40-bits integers and 40-bits pointers, respectively.
 */
template<int bits = 40>
class uint_t {
	static_assert(bits > 0, "bits must be non-negative");
	static_assert(bits < 65, "bits must be at most 64");
	uint64_t data : bits;
	public:
	inline uint_t& operator=(uint64_t& data) { this->data = data; return *this; }
	inline uint_t& operator=(uint64_t&& data) { this->data = data; return *this; }
	inline uint_t& operator=(uint_t<bits>& b) { this->data = b.data; return *this; }
	inline operator uint64_t() const { return data; }
    inline uint_t<bits>& operator--() { --data; return *this;}
    inline uint_t<bits>& operator++() { ++data; return *this;}
    inline uint64_t& operator--(int) { return data--; }
    inline uint64_t& operator++(int) { return data++; }
    inline uint_t<bits>& operator+=(const uint_t<bits>& b) { data += b.data; return *this; }
    inline uint_t<bits>& operator-=(const uint_t<bits>& b) { data -= b.data; return *this; }
    inline uint_t<bits>& operator*=(const uint_t<bits>& b) { data *= b.data; return *this; }
    inline bool operator==(const uint_t<bits>& b) const { return data == b.data; }
    inline bool operator!=(const uint_t<bits>& b) const { return data != b.data; }
    inline bool operator<=(const uint_t<bits>& b) const { return data <= b.data; }
    inline bool operator>=(const uint_t<bits>& b) const { return data >= b.data; }
    inline bool operator<(const uint_t<bits>& b) const { return data < b.data; }
    inline bool operator>(const uint_t<bits>& b) const { return data > b.data; }
} __attribute__((packed));

#endif /* UINT_T_HPP */
<commit_msg>some ops for uint_t<commit_after>#ifndef UINT_T_HPP
#define UINT_T_HPP

#include <cstdint>
/** class for storing integers of arbitrary bits.
 * Useful values are 40,48, and 56.
 * Standard value is 40 bits since we can store values up to 1TiB and
 * address values up to 1TB with 40-bits integers and 40-bits pointers, respectively.
 */
template<int bits = 40>
class uint_t {
	static_assert(bits > 0, "bits must be non-negative");
	static_assert(bits < 65, "bits must be at most 64");
	uint64_t data : bits;
	public:
	uint_t(uint64_t i) : data(i) {}
	uint_t() {}
	uint_t(const uint_t<bits>&& i) : data(i.data) {}
	uint_t(const uint_t<bits>& i) : data(i.data) {}
	inline uint_t& operator=(uint64_t data) { this->data = data; return *this; }
	inline uint_t& operator=(const uint_t<bits>& b) { this->data = b.data; return *this; }
	inline operator uint64_t() const { return data; }
    inline uint_t<bits>& operator--() { --data; return *this;}
    inline uint_t<bits>& operator++() { ++data; return *this;}
    inline uint64_t operator--(int) { return data--; }
    inline uint64_t operator++(int) { return data++; }
    inline uint_t<bits>& operator+=(const uint_t<bits>& b) { data += b.data; return *this; }
    inline uint_t<bits>& operator-=(const uint_t<bits>& b) { data -= b.data; return *this; }
    inline uint_t<bits>& operator*=(const uint_t<bits>& b) { data *= b.data; return *this; }
    inline bool operator==(const uint_t<bits>& b) const { return data == b.data; }
    inline bool operator!=(const uint_t<bits>& b) const { return data != b.data; }
    inline bool operator!=(uint64_t b) const { return data != b; }
    inline bool operator!=(int b) const { return data != b; }
    inline bool operator<=(const uint_t<bits>& b) const { return data <= b.data; }
    inline bool operator>=(const uint_t<bits>& b) const { return data >= b.data; }
    inline bool operator<(const uint_t<bits>& b) const { return data < b.data; }
    inline bool operator<(uint64_t b) const { return data < b; }
    inline bool operator>(uint64_t b) const { return data > b; }
    inline bool operator>(const uint_t<bits>& b) const { return data > b.data; }
} __attribute__((packed));

#endif /* UINT_T_HPP */
<|endoftext|>