text:
#ifndef STREAM_ALIGNER_STREAM_ALIGNER_HPP
#define STREAM_ALIGNER_STREAM_ALIGNER_HPP

#include <stream_aligner/StreamAlignerStatus.hpp>
#include <stream_aligner/CircularArray.hpp>

#include <base/Time.hpp>

#include <boost/function.hpp>

#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <cmath>

namespace stream_aligner
{
    /**
     * StreamBase
     *
     * @brief Base class of Stream
     *
     * */
    class StreamBase
	{
    public:
        /** Stream status (one stream) **/
        mutable StreamStatus status;

        /** marks a stream as active or inactive. All streams are active by default. */
        bool active;

	public:
        StreamBase() : active( true ) {}
        virtual ~StreamBase() {}
        virtual base::Time pop() = 0;
        virtual bool hasData() const = 0;
        virtual int getPriority() const = 0;
        virtual base::Time latestTimeStamp() const = 0;
        virtual base::Time latestDataTime() const = 0;
        virtual base::Time earliestDataTime() const = 0;
        virtual const StreamStatus &getBufferStatus() const = 0;
        virtual void copyState( const StreamBase& other ) = 0;
        virtual void clear() = 0;

        bool isActive() const { return active; }
        void setActive( bool active ) { this->active = active; }

        friend std::ostream &operator<<(std::ostream &stream, const stream_aligner::StreamBase &base);
	};

    /**
     * Stream
     *
     * @brief Stream class of samples
     *
     * T is the template class of the streams.
     * BUFFER_SIZE This should be at least the amount of samples that can occur in a timeout period.
     *
     * */

    template <class T, size_t BUFFER_SIZE>
    class Stream : public StreamBase
	{
	public:

	    typedef boost::function<void (const base::Time &ts, const T &value)> callback_t;

	protected:

        /** Define type of the elements in the buffer **/
	    typedef std::pair<base::Time,T> item;

	protected:
        stream_aligner::CircularArray<item, BUFFER_SIZE> buffer;
	    callback_t callback;
	    base::Time period;
	    base::Time lastTime;
	    int priority;

	public:

	    Stream(callback_t callback, base::Time period, int priority, const std::string &name):
            callback(callback), period(period), lastTime(base::Time::fromSeconds(0)), priority(priority)
        {
            status.name = name;
            status.priority = priority;
            status.buffer_size = buffer.capacity();
        }

	    virtual ~Stream() {};

	    bool getNextSample(item &sample) const
	    {
            if(buffer.empty())
                return false;

            sample = buffer.front();
            return true;
	    }

	    virtual int getPriority() const
	    {
    		return priority;
	    }

	    virtual const StreamStatus &getBufferStatus() const
	    {
            this->status.buffer_fill = buffer.size();
            this->status.latest_data_time = latestDataTime();
            this->status.earliest_data_time = earliestDataTime();
            this->status.active = isActive();
            return status;
	    }

	    virtual void copyState( const StreamBase& other )
	    {
            const Stream<T, BUFFER_SIZE> &stream(dynamic_cast<const Stream<T, BUFFER_SIZE>& >(other));

            lastTime = stream.lastTime;
            buffer = stream.buffer;
            status = stream.status;
	    }

	    void push(const base::Time &ts, const T &data )
	    {
            if(ts < lastTime)
            {
                status.samples_backward_in_time++;
                return;
            }

            lastTime = ts;

            if (buffer.full())
            {
                // if the buffer is full, just use the behaviour of the circular
                // buffer: discard old data.
                status.samples_dropped_buffer_full++;
		    }
            buffer.push_back(std::make_pair(ts, data));
	    }

	    /** take the last item of the stream queue and
	     * call the callback
	     */
	    base::Time pop()
	    {
            if( hasData() )
            {
                status.samples_processed++;
                base::Time ts = buffer.front().first;
                if(callback)
                    callback(ts, buffer.front().second);

                buffer.pop_front();
                return ts;
            }
    		throw std::runtime_error("pop() called on stream with no data.");
	    }

	    bool hasData() const
	    {
            return !buffer.empty();
        }

	    base::Time latestTimeStamp() const
	    {
            if( hasData() )
		        return buffer.front().first;
    		else
    		    return lastTime + period;
	    }

	    virtual base::Time latestDataTime() const
	    {
	    	return lastTime;
	    }

	    virtual base::Time earliestDataTime() const
	    {
            if( hasData() )
                return buffer.front().first;
            return base::Time();
	    }

	    virtual void clear()
	    {
            lastTime = base::Time();
            buffer.clear();

            status.latest_sample_time = base::Time();
            status.latest_data_time = base::Time();
            status.samples_dropped_buffer_full = 0;
            status.samples_dropped_late_arriving = 0;
            status.buffer_fill = 0;
            status.active = true;
	    };

        void print()
        {
            for (stream_aligner::cyclic_iterator<item, BUFFER_SIZE> it(buffer); it.itx() != it.end(); ++it)
            {
                item element = *it;
                std::cout<<"time["<<element.first.toString()<<"]: "<<element.second<<"\n";
            }
        }
	};

    /**
     * Stream Aligner
     *
     * @brief Alignment of streams
     *
     */
    template<size_t NUMBER_STREAMS>
    class StreamAligner
    {

    protected:
	    typedef std::array<StreamBase*, NUMBER_STREAMS> StreamArray;
        template <size_t N> using StreamStatusArray = StreamAlignerStatus<N>; //alias template

    protected:

        /** The streams **/
        StreamArray streams;

        /** The timeout **/
        base::Time timeout;

        /** time of the last sample that came in */
        base::Time latest_ts;

        /** time of the last sample that went out */
        base::Time current_ts;

        /** temporary object that gets returned by getStatus,
         * in order to avoid dynamic allocation on each call */
	    mutable StreamStatusArray<NUMBER_STREAMS> status;

    protected:
        static bool compareStreams( const StreamBase* b1, const StreamBase* b2 )
        {
            if(!b1)
                return false;

            if(!b2)
                return true;

            const base::Time &ts1( b1->latestTimeStamp() );
            const base::Time &ts2( b2->latestTimeStamp() );

            if(ts1 == ts2)
            {
                if(b1->hasData() && !b2->hasData())
                    return true;

                if(!b1->hasData() && b2->hasData())
                    return false;

                return b1->getPriority() < b2->getPriority();
            }

            return ts1 < ts2;
        }

    public:
    	explicit StreamAligner(base::Time timeout = base::Time::fromSeconds(1)): timeout(timeout)
        {
            for(size_t i = 0; i < this->streams.size(); i++)
            {
                this->streams[i] = NULL;
            }
        }

        virtual ~StreamAligner()
        {
    	    for(typename StreamArray::iterator it=this->streams.begin();it != this->streams.end();it++)
            {
                delete *it;
            }
        }

        /** will take the state of other StreamAligner and make it the state of this
         * object. State constitutes current_time and latest_time as well as all the stream
         * content, but not the configuration.
         */
        void copyState(const StreamAligner<NUMBER_STREAMS>& other)
        {
            latest_ts = other.latest_ts;
            current_ts = other.current_ts;

            assert( this->streams.size() == other.streams.size() );
            for(size_t i=0;i<this->streams.size();i++)
            {
                bool weGotStream = this->streams[i];
                bool otherGotStream = other.streams[i];
                if(weGotStream != otherGotStream)
                {
                    throw std::runtime_error("Stream setup of second stream aligner differs");
                }

                if(this->streams[i])
                {
                    this->streams[i]->copyState( *other.streams[i] );
                }
            }
        }

        /** Set the time the Estimator will wait for an expected reading on any of the streams.
         * This number effectively puts an upper limit to the lag that can be created due to
         * delay or missing values on the channels.
         */
        void setTimeout(const base::Time &t)
        {
            timeout = t;
        }

        /**
         * Will disable the stream with the given index.
         *
         * All data left in the stream will still be played out, however the
         * stream will be ignored for lookahead and timeout calculation. A
         * stream, which is disabled can be enabled through the enableStream()
         * call, or if new data in this stream arrives.
         *
         * The functionality is needed for cases where streams might be
         * optional, so that the other streams won't be delayed up to the
         * maximum time out value.
         */
        void disableStream(int idx)
        {
            if(!this->streams[idx])
            throw std::runtime_error("invalid stream index.");

            this->streams[idx]->setActive( false );
        }

        /**
         * Enables a stream which has been disabled previously.
         *
         * All streams are enabled by default. Does not have any effect on
         * streams which are already enabled.
         */
        void enableStream(int idx)
        {
            if(!this->streams[idx])
            throw std::runtime_error("invalid stream index.");

            this->streams[idx]->setActive( true );
        }

        /**
         * See if a stream is enabled or disabled.
         *
         * @return true if the stream is enabled (active)
         */
        bool isStreamActive(int idx) const
        {
            if(!this->streams[idx])
                throw std::runtime_error("invalid stream index.");

            return this->streams[idx]->isActive();
        }

        /**
         * This function will remove the stream with the given index from the
         * stream aligner.
         *
         * @param idx index of the stream that should be unregistered
         */
        void unregisterStream(int idx)
        {
            if(!this->streams[idx])
            {
                throw std::runtime_error("invalid stream index.");
            }

            delete this->streams[idx];

            this->streams[idx] = NULL;

            this->status.streams[idx].active = false;
        }

        /** Will register a stream with the stream_aligner.
         *
         * @param callback - will be called for data gone through the synchronization process
         * @param period - time between sensor readings. This will be used to estimate when the
         *	next reading should arrive, so out of order arrivals are
         *	possible. Set to 0 if not a periodic stream. When set to a
         *	negative value, the calculation of the buffer is performed for
         *	that period, however no lookahead is set.
         * @param priority - if streams have data with equal timestamps, the
         *      one with the lower priority value will be pushed first.
         *
         * @param name - name of the stream. This is only for debug purposes
         *
         * @result - stream index, which is used to identify the stream (e.g. for push).
         */
        template <class T, size_t BUFFER_SIZE> int registerStream( typename Stream<T, BUFFER_SIZE>::callback_t callback, base::Time period, int priority  = -1, const std::string &name = std::string())
        {
            StreamBase *newStream = new Stream<T, BUFFER_SIZE>(callback, period, priority, name);

            /** Store the stream in the first free slot **/
            for(size_t i = 0; i < this->streams.size(); i++)
            {
                if(!this->streams[i])
                {
                    this->streams[i] = newStream;
                    this->status.streams[i] = StreamStatus();
                    return i;
                }
            }
            throw std::runtime_error("Array of streams is FULL");
        }

        /** @brief Push new data into the stream
         *
         * Note that if the stream was previously inactive, this call will make
         * it active implicetely.
         *
         * @param ts - the timestamp of the data item
         * @param data - the data added to the stream
         */
        template <class T, size_t BUFFER_SIZE> void push( int idx, const base::Time &ts, const T& data )
        {
            if( !this->streams.at(idx) )
                throw std::runtime_error("invalid stream index.");

            Stream<T, BUFFER_SIZE>* stream = dynamic_cast<Stream<T, BUFFER_SIZE>*>(this->streams[idx]);
            assert( stream );

            stream->status.samples_received++;
            stream->status.latest_sample_time = ts;

            // mark stream as active, since it is receiving data items will
            // have no effect on an already active stream, but enables
            // streams which have been marked passive before.
            stream->setActive( true );

            //any sample, that is older than the last replayed sample
            //will never be played back and gets dropped by default
            if(ts < current_ts)
            {
                this->status.samples_dropped_late_arriving++;
                stream->status.samples_dropped_late_arriving++;
                return;
            }

            if( ts > latest_ts )
                latest_ts = ts;

            stream->push(ts, data);
        }

        template <class T, size_t BUFFER_SIZE> bool getNextSample( int idx, std::pair<base::Time,T> &sample) const
        {
            if( !this->streams.at(idx) )
                throw std::runtime_error("invalid stream index.");

            Stream<T, BUFFER_SIZE>* stream = dynamic_cast<Stream<T, BUFFER_SIZE>*>(this->streams[idx]);
            assert( stream );

            return stream->getNextSample(sample);
        }

        /** This will go through the available streams and look for the
         * oldest available data. The data can be either existing are predicted
         * through the period.
         *
         * There are three different cases that can happen:
         *  - The data is already available. In this case that data is forwarded
         *    to the callback.
         *  - The data is not yet available, and the time difference between oldest
         *    data and newest data is below the timeout threshold. In this case
         *    no data is called.
         *  - The data is not yet available, and the timeout is reached. In this
         *    case, the oldest data (which is obviously non-available) is ignored,
         *    and only newer data is considered.
         *
         *  @result - true if a callback was called and more data might be available
         */
        bool step()
        {
            /** copy streams vector and sort it by next ts **/
            StreamArray items = this->streams;
            std::sort(items.begin(), items.end(), &compareStreams);

            for(typename StreamArray::iterator it=items.begin();it != items.end();it++)
            {
                /** first stream is unregistered no data there **/
                if(!*it)
                    return false;

                if((*it)->hasData())
                {
                    /** if stream has current data, pop that data **/
                    current_ts = (*it)->pop();
                    return true;
                }
                else if( (*it)->isActive() )
                {
                    base::Time latestDataTime;
                    base::Time firstDataTime;

                    /** initalization case **/
                    if(current_ts == base::Time())
                    {
                        /** check if one stream timed out **/
                        for(typename StreamArray::iterator it2=items.begin();it2 != items.end();it2++)
                        {
                            if(*it2 && (*it2)->hasData())
                            {
                                if(latestDataTime < (*it2)->latestDataTime())
                                    latestDataTime = (*it2)->latestDataTime();

                                if(firstDataTime == base::Time() || firstDataTime > (*it2)->earliestDataTime())
                                    firstDataTime = (*it2)->earliestDataTime();
                            }
                        }
                    }
                    else
                    {
                        latestDataTime = latest_ts;
                        firstDataTime = current_ts;
                    }

                    if(latestDataTime - firstDataTime < timeout)
                    {
                        /** if there is no data, but the expected data has
                        not run out yet, wait for it. **/
                        return false;
                    }
                }
            }
            return false;
        }

        /**
         * clears all samples in all streams, resets the statistics
         * and resets the playback times  but leaves the stream
         * setup intact.
         */
        void clear()
        {
            for(size_t i = 0; i < streams.size(); i++)
            {
                if(streams[i])
                {
                    streams[i]->clear();
                }
            }

            latest_ts = base::Time();
            current_ts = base::Time();

            this->status.current_time = base::Time();
            this->status.latest_time = base::Time();
            this->status.samples_dropped_late_arriving = 0;
        }

        /** Get the time the Estimator will wait for an expected reading on any of the streams.
         * This number effectively puts an upper limit to the lag that can be created due to
         * delay or missing values on the channels.
         */
        base::Time getTimeOut() const { return timeout; };

        /** latency is the time difference between the latest data item that
         * has come in, and the latest data item that went out
         */
        base::Time getLatency() const { return latest_ts - current_ts; };

        /** return the time of the last data item that went out
         */
        base::Time getCurrentTime() const { return current_ts; };

        /** return the time of the last data item that came in
         */
        base::Time getLatestTime() const { return latest_ts; }

        /** return the number of streams
        */
        int getStreamSize() const { return streams.size();  }

        /** return the buffer status as a std::pair. first element in pair is
         * the current buffer fill and the second element is the buffer size
         */
        const StreamStatus &getBufferStatus(int idx) const
        {
            if( !streams.at(idx) )
                throw std::runtime_error("invalid stream index.");
            return streams[idx]->getBufferStatus();
        }

        /** @return the current status of the StreamAligner
         * this is mainly used for debug purposes
         */
        const StreamStatusArray<NUMBER_STREAMS>& getStatus() const
        {
            this->status.time = base::Time::now();
            this->status.current_time = getCurrentTime();
            this->status.latest_time = getLatestTime();

            for(size_t i=0;i<streams.size();i++)
            {
                if(streams[i])
                    this->status.streams[i] = streams[i]->getBufferStatus();
            }

            return this->status;
        }

        friend std::ostream &operator<<(std::ostream &stream, const stream_aligner::StreamBase &base);
    };

    template <size_t N> inline std::ostream &operator<<(std::ostream &stream, const stream_aligner::StreamAligner<N> &re)
    {
        using ::operator <<;
        stream << "current time: " << re.getCurrentTime() << " latest time:" << re.getLatestTime() << " latency: " << re.getLatency() << std::endl;
        for(size_t i=0;i<re.streams.size();i++)
        {
            stream << i << ":" << *re.streams[i] << std::endl;
        }

    	return stream;
    }

    inline std::ostream &operator<<(std::ostream &stream, const stream_aligner::StreamBase &base)
    {
        using ::operator <<;
        stream << base.getBufferStatus();
        return stream;
    }

}

#endif

ext: hpp


text:
/***********************************************************************************************************************
*  OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC, and other contributors. 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.
*
*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
*  derived from this software without specific prior written permission from the respective party.
*
*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
*  written permission from Alliance for Sustainable Energy, LLC.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY 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 HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***********************************************************************************************************************/

#include <algorithm>
#include <gtest/gtest.h>

#include <string>
#include <boost/optional.hpp>

#include "ModelFixture.hpp"

#include "../BuildingUnit.hpp"
#include "../BuildingUnit_Impl.hpp"
#include "../RenderingColor.hpp"
#include "../RenderingColor_Impl.hpp"
#include "../Space.hpp"
#include "../Space_Impl.hpp"
#include "../Surface.hpp"
#include "../Surface_Impl.hpp"

#include "../utilities/geometry/Geometry.hpp"
#include "../../utilities/units/Quantity.hpp"
#include "../../utilities/units/Unit.hpp"

using namespace openstudio;
using namespace openstudio::model;

TEST_F(ModelFixture, BuildingUnit_RenderingColor)
{

  Model model;
  BuildingUnit buildingUnit(model);
  RenderingColor color1(model);

  color1.setRenderingRedValue(255);
  color1.setRenderingGreenValue(0);
  color1.setRenderingBlueValue(0);
  color1.setRenderingAlphaValue(255);

  EXPECT_FALSE(buildingUnit.renderingColor());

  ASSERT_TRUE(buildingUnit.setRenderingColor(color1));

  boost::optional<RenderingColor> color2 = buildingUnit.renderingColor();
  ASSERT_TRUE(color2);

  EXPECT_EQ(color2->renderingRedValue(), 255);
  EXPECT_EQ(color2->renderingGreenValue(), 0);
  EXPECT_EQ(color2->renderingBlueValue(), 0);
  EXPECT_EQ(color2->renderingAlphaValue(), 255);

  buildingUnit.resetRenderingColor();
  ASSERT_FALSE(buildingUnit.renderingColor());

}

TEST_F(ModelFixture, BuildingUnit_BuildingUnitType)
{
  Model model;
  BuildingUnit bldgUnit(model);

  std::vector<std::string> bldgUnitTypeValues(bldgUnit.buildingUnitTypeValues());

  // Make sure both Residential and NonResidential are in the list and that there's only two items.
  EXPECT_NE(std::find(bldgUnitTypeValues.begin(), bldgUnitTypeValues.end(), "Residential"), bldgUnitTypeValues.end());
  EXPECT_NE(std::find(bldgUnitTypeValues.begin(), bldgUnitTypeValues.end(), "NonResidential"), bldgUnitTypeValues.end());
  EXPECT_EQ(bldgUnitTypeValues.size(), 2);

  // Check default
  std::string bldgUnitType = bldgUnit.buildingUnitType();
  EXPECT_EQ(bldgUnitType, "Residential");

  // Assign New and check that the assignment worked.
  EXPECT_TRUE(bldgUnit.setBuildingUnitType("NonResidential"));
  bldgUnitType = bldgUnit.buildingUnitType();
  EXPECT_EQ(bldgUnitType, "NonResidential");

  // Reset and check that its back at the default.
  bldgUnit.resetBuildingUnitType();
  bldgUnitType = bldgUnit.buildingUnitType();
  EXPECT_EQ(bldgUnitType, "Residential");

  // Set it to something invalid
  EXPECT_TRUE(bldgUnit.setBuildingUnitType("NonResidential"));
  EXPECT_FALSE(bldgUnit.setBuildingUnitType("Bogus"));
  bldgUnitType = bldgUnit.buildingUnitType();
  EXPECT_EQ(bldgUnitType, "NonResidential");

}

TEST_F(ModelFixture, BuildingUnit_Spaces)
{
  Model model;
  BuildingUnit bldgUnit(model);
  bldgUnit.setName("Building Unit 1");

  Space space1 = Space(model);
  space1.setName("Space 1");
  EXPECT_TRUE(space1.setBuildingUnit(bldgUnit));
  boost::optional<BuildingUnit> retrievedBldgUnit(space1.buildingUnit());
  ASSERT_TRUE(retrievedBldgUnit);
  EXPECT_EQ(*retrievedBldgUnit, bldgUnit);

  Space space2 = Space(model);
  space2.setName("Space 2");
  EXPECT_TRUE(space2.setBuildingUnit(bldgUnit));

  std::vector<Space> spaces(bldgUnit.spaces());
  EXPECT_EQ(spaces.size(), 2);
  EXPECT_NE(std::find(spaces.begin(), spaces.end(), space1), spaces.end());
  EXPECT_NE(std::find(spaces.begin(), spaces.end(), space2), spaces.end());

  std::vector<Point3d> surf1vert;
  surf1vert.push_back(Point3d(0, 0, 0));
  surf1vert.push_back(Point3d(10, 0, 0));
  surf1vert.push_back(Point3d(10, 10, 0));
  surf1vert.push_back(Point3d(0, 10, 0));
  Surface surf1(surf1vert, model);
  surf1.setSurfaceType("Floor");
  surf1.setSpace(space1);

  std::vector<Point3d> surf2vert;
  surf2vert.push_back(Point3d(10, 0, 0));
  surf2vert.push_back(Point3d(15, 0, 0));
  surf2vert.push_back(Point3d(15, 5, 0));
  surf2vert.push_back(Point3d(10, 5, 0));
  Surface surf2(surf2vert, model);
  surf2.setSurfaceType("Floor");
  surf2.setSpace(space2);

  double floorArea = bldgUnit.floorArea();
  EXPECT_FLOAT_EQ(floorArea, 10 * 10 + 5 * 5);

  space1.resetBuildingUnit();
  retrievedBldgUnit = space1.buildingUnit();
  ASSERT_FALSE(retrievedBldgUnit);
  spaces = bldgUnit.spaces();
  EXPECT_EQ(spaces.size(), 1);
  EXPECT_EQ(spaces.at(0), space2);

}

TEST_F(ModelFixture, BuildingUnit_Features)
{
  Model model;
  BuildingUnit bldgUnit(model);

  // Test initially setting a string value
  EXPECT_TRUE(bldgUnit.setFeature("NumberOfBedrooms", "five"));
  boost::optional<std::string> dataType = bldgUnit.getFeatureDataType("NumberOfBedrooms");
  ASSERT_TRUE(dataType);
  EXPECT_EQ(*dataType, "String");
  boost::optional<std::string> strValue = bldgUnit.getFeatureAsString("NumberOfBedrooms");
  ASSERT_TRUE(strValue);
  EXPECT_EQ(*strValue, "five");

  // Test changing a string value
  EXPECT_TRUE(bldgUnit.setFeature("NumberOfBedrooms", "six"));
  dataType = bldgUnit.getFeatureDataType("NumberOfBedrooms");
  ASSERT_TRUE(dataType);
  EXPECT_EQ(*dataType, "String");
  strValue = bldgUnit.getFeatureAsString("NumberOfBedrooms");
  ASSERT_TRUE(strValue);
  EXPECT_EQ(*strValue, "six");

  // Test setting a boolean value
  EXPECT_TRUE(bldgUnit.setFeature("isNicePlace", false));
  dataType = bldgUnit.getFeatureDataType("isNicePlace");
  ASSERT_TRUE(dataType);
  EXPECT_EQ(*dataType, "Boolean");
  boost::optional<bool> boolValue = bldgUnit.getFeatureAsBoolean("isNicePlace");
  ASSERT_TRUE(boolValue);
  ASSERT_FALSE(*boolValue);

  // Test changing a boolean value
  EXPECT_TRUE(bldgUnit.setFeature("isNicePlace", true));
  dataType = bldgUnit.getFeatureDataType("isNicePlace");
  ASSERT_TRUE(dataType);
  EXPECT_EQ(*dataType, "Boolean");
  boolValue = bldgUnit.getFeatureAsBoolean("isNicePlace");
  ASSERT_TRUE(boolValue);
  ASSERT_TRUE(*boolValue);

  // Test Feature Name getter
  const std::vector<std::string> featureNames(bldgUnit.featureNames());
  EXPECT_EQ(featureNames.size(), 2);
  EXPECT_EQ(featureNames[0], "NumberOfBedrooms");
  EXPECT_EQ(featureNames[1], "isNicePlace");

  // Test setting a double value
  EXPECT_TRUE(bldgUnit.setFeature("NumberOfBathrooms", 1.5));
  dataType = bldgUnit.getFeatureDataType("NumberOfBathrooms");
  ASSERT_TRUE(dataType);
  EXPECT_EQ(*dataType, "Double");
  boost::optional<double> dblValue = bldgUnit.getFeatureAsDouble("NumberOfBathrooms");
  ASSERT_TRUE(dblValue);
  boost::optional<int> intValue = bldgUnit.getFeatureAsInteger("NumberOfBathrooms");
  ASSERT_FALSE(intValue);
  ASSERT_FLOAT_EQ(*dblValue, 1.5);

  // Test setting a feature to a value of a different type
  EXPECT_TRUE(bldgUnit.setFeature("NumberOfBedrooms", 3));
  dataType = bldgUnit.getFeatureDataType("NumberOfBedrooms");
  ASSERT_TRUE(dataType);
  EXPECT_EQ(*dataType, "Integer");
  dblValue = bldgUnit.getFeatureAsDouble("NumberOfBedrooms");
  ASSERT_FALSE(dblValue);
  intValue = bldgUnit.getFeatureAsInteger("NumberOfBedrooms");
  ASSERT_TRUE(intValue);
  ASSERT_EQ(*intValue, 3);

  // Test resetting a feature
  EXPECT_TRUE(bldgUnit.resetFeature("isNicePlace"));
  dataType = bldgUnit.getFeatureDataType("isNicePlace");
  ASSERT_FALSE(dataType);
  EXPECT_FALSE(bldgUnit.resetFeature("bogusName"));

  // Test suggested feature names
  EXPECT_TRUE(bldgUnit.setFeature("MyUniqueFeature", 5));
  BuildingUnit bldgUnit2(model);
  std::vector<std::string> suggestedFeatures(bldgUnit2.suggestedFeatures());
  ASSERT_EQ(suggestedFeatures.size(), 3);
  ASSERT_NE(std::find(suggestedFeatures.begin(), suggestedFeatures.end(), "NumberOfBedrooms"), suggestedFeatures.end());
  ASSERT_NE(std::find(suggestedFeatures.begin(), suggestedFeatures.end(), "NumberOfBathrooms"), suggestedFeatures.end());
  ASSERT_NE(std::find(suggestedFeatures.begin(), suggestedFeatures.end(), "MyUniqueFeature"), suggestedFeatures.end());

}

ext: cpp

max_stars_repo_name: hellok-coder/OS-Testing

max_issues_repo_name: hellok-coder/OS-Testing

max_forks_repo_name: hellok-coder/OS-Testing


text:
#pragma once

#include <ysu/lib/numbers.hpp>
#include <ysu/lib/utility.hpp>
#include <ysu/secure/common.hpp>

#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>

#include <chrono>
#include <memory>
#include <mutex>
#include <vector>

namespace ysu
{
class node;
class transaction;

/** For each gap in account chains, track arrival time and voters */
class gap_information final
{
public:
	std::chrono::steady_clock::time_point arrival;
	ysu::block_hash hash;
	std::vector<ysu::account> voters;
	bool bootstrap_started{ false };
};

/** Maintains voting and arrival information for gaps (missing source or previous blocks in account chains) */
class gap_cache final
{
public:
	explicit gap_cache (ysu::node &);
	void add (ysu::block_hash const &, std::chrono::steady_clock::time_point = std::chrono::steady_clock::now ());
	void erase (ysu::block_hash const & hash_a);
	void vote (std::shared_ptr<ysu::vote>);
	bool bootstrap_check (std::vector<ysu::account> const &, ysu::block_hash const &);
	void bootstrap_start (ysu::block_hash const & hash_a);
	ysu::uint128_t bootstrap_threshold ();
	size_t size ();
	// clang-format off
	class tag_arrival {};
	class tag_hash {};
	using ordered_gaps = boost::multi_index_container<ysu::gap_information,
	boost::multi_index::indexed_by<
		boost::multi_index::ordered_non_unique<boost::multi_index::tag<tag_arrival>,
			boost::multi_index::member<gap_information, std::chrono::steady_clock::time_point, &gap_information::arrival>>,
		boost::multi_index::hashed_unique<boost::multi_index::tag<tag_hash>,
			boost::multi_index::member<gap_information, ysu::block_hash, &gap_information::hash>>>>;
	ordered_gaps blocks;
	// clang-format on
	size_t const max = 256;
	std::mutex mutex;
	ysu::node & node;
};

std::unique_ptr<container_info_component> collect_container_info (gap_cache & gap_cache, const std::string & name);
}


text:
// Copyright (c) 2012, Yahoo! Inc.  All rights reserved.
// Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.

#include <gearbox/core/Json.h>
#include <gearbox/core/JsonSchema.h>
using namespace Gearbox;

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

#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>

namespace opt = boost::program_options;
#include <unistd.h>

int main(int argc, char **argv)
{
    opt::options_description options("Options");

    try {
        options.add_options()
            ("help,h", "produce this help message")
            ("schema,s", opt::value<std::string>(), "Validate against the specified schema")
            ("pretty,p", "pretty-print (indent) the output")
            ("data,d", "operate on the embedded \"data\" json string")
            ;

        opt::variables_map args;
        {
            // The option to receive positional args is hidden from the help output
            opt::options_description options2;
            options2.add(options).add_options()("input", opt::value<std::string>(), "Input file");

            opt::positional_options_description positional;
            positional.add("input", -1);

            opt::store(opt::command_line_parser(argc, argv).options(options2).positional(positional).run(), args);
            opt::notify(args);
        }

        if (args.count("help")) {
            std::cout << options << std::endl;
            return 0;
        }

        std::string input;

        if (args.count("input")) {
            input = args["input"].as<std::string>();
        }
        else {
            input = "/dev/stdin";

            // this is probably not what the user intended, so warn them
            if (isatty(0)) {
                std::cerr << "Please type in JSON or hit Ctrl-C (stdin is a tty)" << std::endl;
            }
        }

        Json json;
        json.parseFile(input);

        if (args.count("data")) {
            Json tmp;
            tmp.parse(json["data"].as<std::string>());
            json = tmp;
        }

        if (args.count("schema")) {
            JsonSchema schema;
            schema.parseFile(args["schema"].as<std::string>());

            if (!json.validate(&schema)) {
                std::cerr << "ERROR: Schema validation failed" << std::endl;
                return 2;
            }
        }

        bool pretty = args.count("pretty");
        std::string res = json.serialize(pretty);
        if (!res.empty() && res.at(res.size()-1) != '\n') {
            res += "\n";
        }
        std::cout << res;

        return 0;
    }
    catch (const opt::error& err) {
        // opt::error is thrown for usage errors, by the options parser, or by our code
        std::cerr << options << std::endl << "Usage error: " << err.what() << std::endl;
        return 1;
    }
    catch (const std::exception& exc) {
        std::cerr << "ERROR: " << exc.what() << std::endl;
        return 2;
    }
}

/* Style Settings:
 *
 * Local Variables:
 *   mode: C++
 *   indent-tabs-mode: nil
 *   c-basic-offset: 4
 *   c-set-style: "knr"
 * End:
 * vim:set sw=4 ts=4 sts=4 cindent expandtab cinoptions=(0:
 */

ext: cc

max_stars_repo_name: coryb/gearbox

max_issues_repo_name: coryb/gearbox

max_forks_repo_name: coryb/gearbox


text:
// Copyright 2012 Cloudera Inc.
//
// 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.

#include "util/codec.h"
#include <boost/assign/list_of.hpp>

#include "util/compress.h"
#include "util/decompress.h"

#include "gen-cpp/CatalogObjects_types.h"
#include "gen-cpp/CatalogObjects_constants.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace impala;

const char* const Codec::DEFAULT_COMPRESSION =
    "org.apache.hadoop.io.compress.DefaultCodec";

const char* const Codec::GZIP_COMPRESSION =
    "org.apache.hadoop.io.compress.GzipCodec";

const char* const Codec::BZIP2_COMPRESSION =
    "org.apache.hadoop.io.compress.BZip2Codec";

const char* const Codec::SNAPPY_COMPRESSION =
    "org.apache.hadoop.io.compress.SnappyCodec";

const char* const UNKNOWN_CODEC_ERROR =
    "This compression codec is currently unsupported: ";

const Codec::CodecMap Codec::CODEC_MAP = map_list_of
  ("", THdfsCompression::NONE)
  (Codec::DEFAULT_COMPRESSION, THdfsCompression::DEFAULT)
  (Codec::GZIP_COMPRESSION, THdfsCompression::GZIP)
  (Codec::BZIP2_COMPRESSION, THdfsCompression::BZIP2)
  (Codec::SNAPPY_COMPRESSION, THdfsCompression::SNAPPY_BLOCKED);

string Codec::GetCodecName(THdfsCompression::type type) {
  map<const string, THdfsCompression::type>::const_iterator im;
  for (im = g_CatalogObjects_constants.COMPRESSION_MAP.begin();
       im != g_CatalogObjects_constants.COMPRESSION_MAP.end(); ++im) {
    if (im->second == type) return im->first;
  }
  DCHECK(im != g_CatalogObjects_constants.COMPRESSION_MAP.end());
  return "INVALID";
}

Status Codec::CreateCompressor(MemPool* mem_pool, bool reuse, const string& codec,
                               scoped_ptr<Codec>* compressor) {
  map<const string, const THdfsCompression::type>::const_iterator
      type = CODEC_MAP.find(codec);

  if (type == CODEC_MAP.end()) {
    stringstream ss;
    ss << UNKNOWN_CODEC_ERROR << codec;
    return Status(ss.str());
  }
  Codec* comp;
  RETURN_IF_ERROR(
      CreateCompressor(mem_pool, reuse, type->second, &comp));
  compressor->reset(comp);
  return Status::OK;
}

Status Codec::CreateCompressor(MemPool* mem_pool, bool reuse,
                               THdfsCompression::type format,
                               scoped_ptr<Codec>* compressor) {
  Codec* comp;
  RETURN_IF_ERROR(
      CreateCompressor(mem_pool, reuse, format, &comp));
  compressor->reset(comp);
  return Status::OK;
}

Status Codec::CreateCompressor(MemPool* mem_pool, bool reuse,
                               THdfsCompression::type format,
                               Codec** compressor) {
  switch (format) {
    case THdfsCompression::NONE:
      *compressor = NULL;
      return Status::OK;
    case THdfsCompression::GZIP:
      *compressor = new GzipCompressor(GzipCompressor::GZIP, mem_pool, reuse);
      break;
    case THdfsCompression::DEFAULT:
      *compressor = new GzipCompressor(GzipCompressor::ZLIB, mem_pool, reuse);
      break;
    case THdfsCompression::DEFLATE:
      *compressor = new GzipCompressor(GzipCompressor::DEFLATE, mem_pool, reuse);
      break;
    case THdfsCompression::BZIP2:
      *compressor = new BzipCompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY_BLOCKED:
      *compressor = new SnappyBlockCompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY:
      *compressor = new SnappyCompressor(mem_pool, reuse);
      break;
    default: {
      stringstream ss;
      ss << "Unsupported codec: " << format;
      return Status(ss.str());
    }
  }

  return (*compressor)->Init();
}

Status Codec::CreateDecompressor(MemPool* mem_pool, bool reuse, const string& codec,
                                 scoped_ptr<Codec>* decompressor) {
  map<const string, const THdfsCompression::type>::const_iterator
      type = CODEC_MAP.find(codec);

  if (type == CODEC_MAP.end()) {
    stringstream ss;
    ss << UNKNOWN_CODEC_ERROR << codec;
    return Status(ss.str());
  }
  Codec* decom;
  RETURN_IF_ERROR(
      CreateDecompressor(mem_pool, reuse, type->second, &decom));
  decompressor->reset(decom);
  return Status::OK;
}

Status Codec::CreateDecompressor(MemPool* mem_pool, bool reuse,
                                 THdfsCompression::type format,
                                 scoped_ptr<Codec>* decompressor) {
  Codec* decom;
  RETURN_IF_ERROR(
      CreateDecompressor(mem_pool, reuse, format, &decom));
  decompressor->reset(decom);
  return Status::OK;
}

Status Codec::CreateDecompressor(MemPool* mem_pool, bool reuse,
                                 THdfsCompression::type format,
                                 Codec** decompressor) {
  switch (format) {
    case THdfsCompression::NONE:
      *decompressor = NULL;
      return Status::OK;
    case THdfsCompression::DEFAULT:
    case THdfsCompression::GZIP:
      *decompressor = new GzipDecompressor(mem_pool, reuse, false);
      break;
    case THdfsCompression::DEFLATE:
      *decompressor = new GzipDecompressor(mem_pool, reuse, true);
      break;
    case THdfsCompression::BZIP2:
      *decompressor = new BzipDecompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY_BLOCKED:
      *decompressor = new SnappyBlockDecompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY:
      *decompressor = new SnappyDecompressor(mem_pool, reuse);
      break;
    default: {
      stringstream ss;
      ss << "Unsupported codec: " << format;
      return Status(ss.str());
    }
  }

  return (*decompressor)->Init();
}

Codec::Codec(MemPool* mem_pool, bool reuse_buffer)
  : memory_pool_(mem_pool),
    reuse_buffer_(reuse_buffer),
    out_buffer_(NULL),
    buffer_length_(0) {
  if (memory_pool_ != NULL) {
    temp_memory_pool_.reset(new MemPool(memory_pool_->mem_tracker()));
  }
}

void Codec::Close() {
  if (temp_memory_pool_.get() != NULL) {
    DCHECK(memory_pool_ != NULL);
    memory_pool_->AcquireData(temp_memory_pool_.get(), false);
  }
}

max_stars_repo_name: Altiscale/Impala

max_issues_repo_name: Altiscale/Impala

max_forks_repo_name: Altiscale/Impala


text:
//---------------------------------------------------------------------------//
// Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
// Copyright (c) 2020 Nikita Kaskov <nbering@nil.foundation>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//---------------------------------------------------------------------------//

#ifndef CRYPTO3_RIPEMD_FUNCTIONS_HPP
#define CRYPTO3_RIPEMD_FUNCTIONS_HPP

#include <boost/crypto3/hash/detail/ripemd/ripemd_policy.hpp>

namespace boost {
    namespace crypto3 {
        namespace hashes {
            namespace detail {
                template<std::size_t DigestBits>
                struct ripemd_functions : public ripemd_policy<DigestBits> {
                    typedef ripemd_policy<DigestBits> policy_type;

                    typedef typename policy_type::word_type word_type;

                    struct f1 {
                        inline word_type operator()(word_type x, word_type y, word_type z) const {
                            return x ^ y ^ z;
                        }
                    };

                    struct f2 {
                        inline word_type operator()(word_type x, word_type y, word_type z) const {
                            return (x & y) | (~x & z);
                        }
                    };

                    struct f3 {
                        inline word_type operator()(word_type x, word_type y, word_type z) const {
                            return (x | ~y) ^ z;
                        }
                    };

                    struct f4 {
                        inline word_type operator()(word_type x, word_type y, word_type z) const {
                            return (x & z) | (y & ~z);
                        }
                    };

                    struct f5 {
                        inline word_type operator()(word_type x, word_type y, word_type z) const {
                            return x ^ (y | ~z);
                        }
                    };

                    template<typename F>
                    inline static void transform(word_type &a, word_type &b, word_type &c, word_type &d, word_type x,
                                                 word_type k, word_type s) {
                        word_type T = policy_type::rotl(a + F()(b, c, d) + x + k, s);
                        a = d;
                        d = c;
                        c = b;
                        b = T;
                    }

                    template<typename Functor>
                    inline static void transform(word_type &a, word_type &b, word_type &c, word_type &d, word_type &e,
                                                 word_type x, word_type k, word_type s) {
                        word_type T = policy_type::rotl(a + Functor()(b, c, d) + x + k, s) + e;
                        a = e;
                        e = d;
                        d = policy_type::template rotl<10>(c);
                        c = b;
                        b = T;
                    }
                };
            }    // namespace detail
        }        // namespace hashes
    }            // namespace crypto3
}    // namespace boost

#endif    // CRYPTO3_RIPEMD_FUNCTIONS_HPP

max_stars_repo_name: NilFoundation/boost-crypto

max_issues_repo_name: NilFoundation/boost-crypto

max_forks_repo_name: NilFoundation/boost-crypto


text:
#include "androidpath.hpp"

#if defined(__ANDROID__)

#include <cstdlib>
#include <cstring>
#include <pwd.h>
#include <unistd.h>
#include <boost/filesystem/fstream.hpp>

namespace
{
    boost::filesystem::path getUserHome()
    {
        const char* dir = getenv("HOME");
        if (dir == NULL)
        {
            struct passwd* pwd = getpwuid(getuid());
            if (pwd != NULL)
            {
                dir = pwd->pw_dir;
            }
        }
        if (dir == NULL)
            return boost::filesystem::path();
        else
            return boost::filesystem::path(dir);
    }

    boost::filesystem::path getEnv(const std::string& envVariable, const boost::filesystem::path& fallback)
    {
        const char* result = getenv(envVariable.c_str());
        if (!result)
            return fallback;
        boost::filesystem::path dir(result);
        if (dir.empty())
            return fallback;
        else
            return dir;
    }
}

/**
 * \namespace Files
 */
namespace Files
{

AndroidPath::AndroidPath(const std::string& application_name)
    : mName(application_name)
{
}

boost::filesystem::path AndroidPath::getUserConfigPath() const
{
    return getEnv("XDG_CONFIG_HOME",  "/sdcard/libopenmw/config") / mName;
}

boost::filesystem::path AndroidPath::getUserDataPath() const
{
    return getEnv("XDG_DATA_HOME", "/sdcard/libopenmw/share") / mName;
}

boost::filesystem::path AndroidPath::getCachePath() const
{
    return getEnv("XDG_CACHE_HOME", "/sdcard/libopenmw/cache") / mName;
}

boost::filesystem::path AndroidPath::getGlobalConfigPath() const
{
    boost::filesystem::path globalPath("/sdcard/libopenmw/");
    return globalPath / mName;
}

boost::filesystem::path AndroidPath::getLocalPath() const
{
    return boost::filesystem::path("./");
}

boost::filesystem::path AndroidPath::getGlobalDataPath() const
{
    boost::filesystem::path globalDataPath("/sdcard/libopenmw/data");
    return globalDataPath / mName;
}

boost::filesystem::path AndroidPath::getInstallPath() const
{
    return boost::filesystem::path();
}

} /* namespace Files */

#endif /* defined(__Android__) */

max_stars_repo_name: Bodillium/openmw

max_issues_repo_name: Bodillium/openmw

max_forks_repo_name: Bodillium/openmw


text:
// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information.

#include <PMC/Serialize.hpp>

#include <boost/archive/polymorphic_binary_oarchive.hpp>
#include <boost/archive/polymorphic_binary_iarchive.hpp>

#include <boost/archive/polymorphic_text_oarchive.hpp>
#include <boost/archive/polymorphic_text_iarchive.hpp>

#include <boost/archive/polymorphic_xml_oarchive.hpp>
#include <boost/archive/polymorphic_xml_iarchive.hpp>

#include <sstream>
#include <stdexcept>

std::string PMCC::serialize(const PMCC &object, const std::string &format)
{
    std::stringstream ss;

    if (format == "BINARY")
    {
        boost::archive::polymorphic_binary_oarchive oa(ss);
        oa << object;
    }
    else if (format == "TEXT")
    {
        boost::archive::polymorphic_text_oarchive oa(ss);
        oa << object;
    }
    else if (format == "XML")
    {
        boost::archive::polymorphic_xml_oarchive oa(ss);
        oa << object;
    }
    else throw std::invalid_argument("PMCC::serialize unknown format: " + format);

    return ss.str();
}

PMCC PMCC::deserialize(const std::string &data, const std::string &format)
{
    std::stringstream ss(data);
    PMCC object;

    if (format == "BINARY")
    {
        boost::archive::polymorphic_binary_iarchive ia(ss);
        ia >> object;
    }
    else if (format == "TEXT")
    {
        boost::archive::polymorphic_text_iarchive ia(ss);
        ia >> object;
    }
    else if (format == "XML")
    {
        boost::archive::polymorphic_xml_iarchive ia(ss);
        ia >> object;
    }
    else throw std::invalid_argument("PMCC::serialize unknown format: " + format);

    return object;
}

max_stars_repo_name: guruofquality/PMC

max_issues_repo_name: guruofquality/PMC

max_forks_repo_name: guruofquality/PMC


text:
#ifndef FALCON_TYPE_TRAITS_IS_ITERATOR_HPP
#define FALCON_TYPE_TRAITS_IS_ITERATOR_HPP

#include <falcon/type_traits/integral_constant.hpp>
#include <falcon/helper/has_iterator_category.hpp>
#include <falcon/c++/boost_or_std.hpp>
#if __cplusplus < 201103L
#include <boost/type_traits/is_pointer.hpp>
#endif

namespace falcon {

template<typename T>
struct is_iterator
: falcon::integral_constant<bool,
	has_iterator_category<T>::value
	|| FALCON_BOOST_OR_STD_NAMESPACE::is_pointer<T>::value
> {};

template<typename T, std::size_t N>
struct is_iterator<T[N]>
: falcon::false_type
{};

}

#endif

max_stars_repo_name: jonathanpoelen/falcon

max_issues_repo_name: jonathanpoelen/falcon

max_forks_repo_name: jonathanpoelen/falcon


text:
/*
 *  Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 *
 */

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
#include <typeinfo>
#include <vector>

#ifdef HIGHFIVE_CPP11_ENABLE
#include <memory>
#endif

#include <stdio.h>

#include <highfive/H5File.hpp>
#include <highfive/H5DataSet.hpp>
#include <highfive/H5DataSpace.hpp>
#include <highfive/H5Group.hpp>
#include <highfive/H5Utility.hpp>

#define BOOST_TEST_MAIN HighFiveTest

#include <boost/mpl/list.hpp>
#include <boost/test/unit_test.hpp>

#ifdef H5_USE_BOOST
#include <boost/multi_array.hpp>
#endif

using namespace HighFive;

typedef boost::mpl::list<float, double> floating_numerics_test_types;
typedef boost::mpl::list<int, unsigned int, long, unsigned long, unsigned char,
                         char, float, double, long long, unsigned long long>
    numerical_test_types;
typedef boost::mpl::list<int, unsigned int, long, unsigned long, unsigned char,
                         char, float, double, std::string>
    dataset_test_types;

template <typename T, typename Func>
void generate2D(T* table, size_t x, size_t y, Func& func) {
    for (size_t i = 0; i < x; i++) {
        for (size_t j = 0; j < y; j++) {
            table[i][j] = func();
        }
    }
}

template <typename T, typename Func>
void generate2D(std::vector<std::vector<T> >& vec, size_t x, size_t y,
                Func& func) {
    vec.resize(x);
    for (size_t i = 0; i < x; i++) {
        vec[i].resize(y);
        for (size_t j = 0; j < y; j++) {
            vec[i][j] = func();
        }
    }
}

template <typename T>
struct ContentGenerate {
    ContentGenerate(T init_val = T(0), T inc_val = T(1) + T(1) / T(10))
        : _init(init_val), _inc(inc_val) {}

    T operator()() {
        T ret = _init;
        _init += _inc;
        return ret;
    }

    T _init, _inc;
};

template <>
struct ContentGenerate<char> {
    ContentGenerate() : _init('a') {}

    char operator()() {
        char ret = _init;
        if (++_init >= ('a' + 26))
            _init = 'a';
        return ret;
    }

    char _init;
};

template <>
struct ContentGenerate<std::string> {
    ContentGenerate() {}

    std::string operator()() {
        ContentGenerate<char> gen;
        std::string random_string;
        const size_t size_string = std::rand() % 1000;
        random_string.resize(size_string);
        std::generate(random_string.begin(), random_string.end(), gen);
        return random_string;
    }
};

BOOST_AUTO_TEST_CASE(HighFiveBasic) {

    const std::string FILE_NAME("h5tutr_dset.h5");
    const std::string DATASET_NAME("dset");

    // Create a new file using the default property lists.
    File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

    BOOST_CHECK_EQUAL(file.getName(), FILE_NAME);

    // Create the data space for the dataset.
    std::vector<size_t> dims;
    dims.push_back(4);
    dims.push_back(6);

    DataSpace dataspace(dims);

    // check if the dataset exist
    bool dataset_exist = file.exist(DATASET_NAME + "_double");
    BOOST_CHECK_EQUAL(dataset_exist, false);

    // Create a dataset with double precision floating points
    DataSet dataset_double = file.createDataSet(
        DATASET_NAME + "_double", dataspace, AtomicType<double>());

    BOOST_CHECK_EQUAL(file.getObjectName(0), DATASET_NAME + "_double");

    {
        // check if it exist again
        dataset_exist = file.exist(DATASET_NAME + "_double");
        BOOST_CHECK_EQUAL(dataset_exist, true);

        // and also try to recreate it to the sake of exception testing
        BOOST_CHECK_THROW(
            {
                DataSet fail_duplicated = file.createDataSet(
                    DATASET_NAME + "_double", dataspace, AtomicType<double>());
            },
            DataSetException);
    }

    DataSet dataset_size_t =
        file.createDataSet<size_t>(DATASET_NAME + "_size_t", dataspace);
}

BOOST_AUTO_TEST_CASE(HighFiveSilence) {

    // Setting up a buffer for stderr so we can detect if the stack trace
    // was disabled
    fflush(stderr);
    char buffer[1024];
    memset(buffer, 0, sizeof(char) * 1024);
    setvbuf(stderr, buffer, _IOLBF, 1023);

    try
    {
        SilenceHDF5 silence;
        File file("nonexistent", File::ReadOnly);
    }
    catch (const FileException&)
    {}
    BOOST_CHECK_EQUAL(buffer[0], '\0');

    // restore the dyn allocated buffer
    // or using stderr will segfault when buffer get out of scope
    fflush(stderr);
    setvbuf(stderr, NULL, _IONBF, 0);
}

BOOST_AUTO_TEST_CASE(HighFiveException) {

    // Create a new file
    File file1("random_file_123",
               File::ReadWrite | File::Create | File::Truncate);

    BOOST_CHECK_THROW(
        {
            // triggers a file creation conflict
            File file2("random_file_123", File::ReadWrite | File::Create);
        },
        FileException);
}

BOOST_AUTO_TEST_CASE(HighFiveGroupAndDataSet) {

    const std::string FILE_NAME("h5_group_test.h5");
    const std::string DATASET_NAME("dset");
    const std::string GROUP_NAME1("/group1");
    const std::string GROUP_NAME2("group2");
    const std::string GROUP_NESTED_NAME("group_nested");

    {
        // Create a new file using the default property lists.
        File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

        // absolute group
        file.createGroup(GROUP_NAME1);
        // nested group absolute
        file.createGroup(GROUP_NAME1 + "/" + GROUP_NESTED_NAME);
        // relative group
        Group g1 = file.createGroup(GROUP_NAME2);
        // relative group
        Group nested = g1.createGroup(GROUP_NESTED_NAME);

        // Create the data space for the dataset.
        std::vector<size_t> dims;
        dims.push_back(4);
        dims.push_back(6);

        DataSpace dataspace(dims);

        DataSet dataset_absolute = file.createDataSet(
            GROUP_NAME1 + "/" + GROUP_NESTED_NAME + "/" + DATASET_NAME,
            dataspace, AtomicType<double>());

        DataSet dataset_relative =
            nested.createDataSet(DATASET_NAME, dataspace, AtomicType<double>());
    }
    // read it back
    {
        File file(FILE_NAME, File::ReadOnly);
        Group g1 = file.getGroup(GROUP_NAME1);
        Group g2 = file.getGroup(GROUP_NAME2);
        Group nested_group2 = g2.getGroup(GROUP_NESTED_NAME);

        DataSet dataset_absolute = file.getDataSet(
            GROUP_NAME1 + "/" + GROUP_NESTED_NAME + "/" + DATASET_NAME);
        BOOST_CHECK_EQUAL(4, dataset_absolute.getSpace().getDimensions()[0]);

        DataSet dataset_relative = nested_group2.getDataSet(DATASET_NAME);
        BOOST_CHECK_EQUAL(4, dataset_relative.getSpace().getDimensions()[0]);
    }
}

#ifdef HIGHFIVE_CPP11_ENABLE
BOOST_AUTO_TEST_CASE(HighFiveRefCountMove) {

    const std::string FILE_NAME("h5_ref_count_test.h5");
    const std::string DATASET_NAME("dset");
    const std::string GROUP_NAME1("/group1");
    const std::string GROUP_NAME2("/group2");

    // Create a new file using the default property lists.
    File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

    std::unique_ptr<DataSet> d1_ptr;
    std::unique_ptr<Group> g_ptr;

    {

        // create group
        Group g1 = file.createGroup(GROUP_NAME1);

        // override object
        g1 = file.createGroup(GROUP_NAME2);

        // Create the data space for the dataset.
        std::vector<size_t> dims = { 10 , 10 };

        DataSpace dataspace(dims);

        DataSet d1 = file.createDataSet(
            GROUP_NAME1 + DATASET_NAME,
            dataspace, AtomicType<double>());

        double values[10][10] = { 0 };
        values[5][0] = 1;
        d1.write(values);

        // force move
        d1_ptr.reset( new DataSet(std::move(d1)));

        // force copy
        g_ptr.reset(new Group(g1));

    }
    // read it back
    {
        DataSet d2(std::move(*d1_ptr));
        d1_ptr.reset();

        double values[10][10];
        memset(values, 255, 10*10);

        d2.read(values);

        for(std::size_t i =0; i < 10; ++i){
            for(std::size_t j =0;  j < 10; ++j){
                double v = values[i][j];

                if( i == 5 && j == 0){
                    BOOST_CHECK_EQUAL(v, 1);
                }else{
                    BOOST_CHECK_EQUAL(v, 0);
                }
            }
        }

        // force copy
        Group g2 = *g_ptr;

        // add a subgroup
        g2.createGroup("blabla");

    }
}

#endif

BOOST_AUTO_TEST_CASE(HighFiveSimpleListing) {

    const std::string FILE_NAME("h5_list_test.h5");

    const std::string GROUP_NAME_CORE("group_name");

    const std::string GROUP_NESTED_NAME("/group_nested");

    // Create a new file using the default property lists.
    File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

    {
        // absolute group
        for (int i = 0; i < 2; ++i) {
            std::ostringstream ss;
            ss << "/" << GROUP_NAME_CORE << "_" << i;
            file.createGroup(ss.str());
        }

        size_t n_elem = file.getNumberObjects();
        BOOST_CHECK_EQUAL(2, n_elem);

        std::vector<std::string> elems = file.listObjectNames();
        BOOST_CHECK_EQUAL(2, elems.size());
        std::vector<std::string> reference_elems;
        for (int i = 0; i < 2; ++i) {
            std::ostringstream ss;
            ss << GROUP_NAME_CORE << "_" << i;
            reference_elems.push_back(ss.str());
        }

        BOOST_CHECK_EQUAL_COLLECTIONS(elems.begin(), elems.end(),
                                      reference_elems.begin(),
                                      reference_elems.end());
    }

    {
        file.createGroup(GROUP_NESTED_NAME);
        Group g_nest = file.getGroup(GROUP_NESTED_NAME);

        for (int i = 0; i < 50; ++i) {
            std::ostringstream ss;
            ss << GROUP_NAME_CORE << "_" << i;
            g_nest.createGroup(ss.str());
        }

        size_t n_elem = g_nest.getNumberObjects();
        BOOST_CHECK_EQUAL(50, n_elem);

        std::vector<std::string> elems = g_nest.listObjectNames();
        BOOST_CHECK_EQUAL(50, elems.size());
        std::vector<std::string> reference_elems;

        for (int i = 0; i < 50; ++i) {
            std::ostringstream ss;
            ss << GROUP_NAME_CORE << "_" << i;
            reference_elems.push_back(ss.str());
        }
        // there is no guarantee on the order of the hdf5 index, let's sort it
        // to put them in order
        std::sort(elems.begin(), elems.end());
        std::sort(reference_elems.begin(), reference_elems.end());

        BOOST_CHECK_EQUAL_COLLECTIONS(elems.begin(), elems.end(),
                                      reference_elems.begin(),
                                      reference_elems.end());
    }
}

BOOST_AUTO_TEST_CASE(DataTypeEqualSimple) {

    using namespace HighFive;

    AtomicType<double> d_var;

    AtomicType<size_t> size_var;

    AtomicType<double> d_var_test;

    AtomicType<size_t> size_var_cpy(size_var);

    AtomicType<int> int_var;
    AtomicType<unsigned int> uint_var;

    // check different type matching
    BOOST_CHECK(d_var == d_var_test);
    BOOST_CHECK(d_var != size_var);

    // check type copy matching
    BOOST_CHECK(size_var_cpy == size_var);

    // check sign change not matching
    BOOST_CHECK(int_var != uint_var);
}

BOOST_AUTO_TEST_CASE(DataTypeEqualTakeBack) {

    using namespace HighFive;

    const std::string FILE_NAME("h5tutr_dset.h5");
    const std::string DATASET_NAME("dset");

    // Create a new file using the default property lists.
    File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

    // Create the data space for the dataset.
    std::vector<size_t> dims;
    dims.push_back(10);
    dims.push_back(1);

    DataSpace dataspace(dims);

    // Create a dataset with double precision floating points
    DataSet dataset =
        file.createDataSet<size_t>(DATASET_NAME + "_double", dataspace);

    AtomicType<size_t> s;
    AtomicType<double> d;

    BOOST_CHECK(s == dataset.getDataType());
    BOOST_CHECK(d != dataset.getDataType());
}

BOOST_AUTO_TEST_CASE(DataSpaceTest) {

    using namespace HighFive;

    const std::string FILE_NAME("h5tutr_space.h5");
    const std::string DATASET_NAME("dset");

    // Create a new file using the default property lists.
    File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

    // Create the data space for the dataset.
    std::vector<size_t> dims;
    dims.push_back(10);
    dims.push_back(1);

    DataSpace dataspace(dims);

    // Create a dataset with size_t type
    DataSet dataset = file.createDataSet<size_t>(DATASET_NAME, dataspace);

    DataSpace space = dataset.getSpace();
    DataSpace space2 = dataset.getSpace();

    // verify space id are different
    BOOST_CHECK_NE(space.getId(), space2.getId());

    // verify space id are consistent
    BOOST_CHECK_EQUAL(space.getDimensions().size(), 2);
    BOOST_CHECK_EQUAL(space.getDimensions()[0], 10);
    BOOST_CHECK_EQUAL(space.getDimensions()[1], 1);
}

template <typename T>
void readWrite2DArrayTest() {

    std::ostringstream filename;
    filename << "h5_rw_2d_array_" << typeid(T).name() << "_test.h5";

    const std::string DATASET_NAME("dset");

    const size_t x_size = 100;
    const size_t y_size = 10;

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    // Create the data space for the dataset.
    std::vector<size_t> dims;
    dims.push_back(x_size);
    dims.push_back(y_size);

    DataSpace dataspace(dims);

    // Create a dataset with arbitrary type
    DataSet dataset = file.createDataSet<T>(DATASET_NAME, dataspace);

    T array[x_size][y_size];

    ContentGenerate<T> generator;
    generate2D(array, x_size, y_size, generator);

    dataset.write(array);

    T result[x_size][y_size];

    dataset.read(result);

    for (size_t i = 0; i < x_size; ++i) {
        for (size_t j = 0; j < y_size; ++j) {
            BOOST_CHECK_EQUAL(result[i][j], array[i][j]);
        }
    }
}

BOOST_AUTO_TEST_CASE_TEMPLATE(ReadWrite2DArray, T, numerical_test_types) {

    readWrite2DArrayTest<T>();
}

template <typename T>
void readWriteVectorTest() {
    using namespace HighFive;

    std::ostringstream filename;
    filename << "h5_rw_vec_" << typeid(T).name() << "_test.h5";

    std::srand((unsigned int)std::time(0));
    const size_t x_size = 800;
    const std::string DATASET_NAME("dset");
    typename std::vector<T> vec;

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    // Create a dataset with double precision floating points
    DataSet dataset = file.createDataSet<T>(DATASET_NAME, DataSpace::From(vec));

    dataset.write(vec);

    typename std::vector<T> result;

    dataset.read(result);

    BOOST_CHECK_EQUAL(vec.size(), x_size);
    BOOST_CHECK_EQUAL(result.size(), x_size);

    for (size_t i = 0; i < x_size; ++i) {
        // std::cout << result[i] << " " << vec[i] << "  ";
        BOOST_CHECK_EQUAL(result[i], vec[i]);
    }
}

template <typename T>
void readWriteAttributeVectorTest() {
    using namespace HighFive;

    std::ostringstream filename;
    filename << "h5_rw_attribute_vec_" << typeid(T).name() << "_test.h5";

    std::srand((unsigned int)std::time(0));
    const size_t x_size = 25;
    const std::string DATASET_NAME("dset");
    typename std::vector<T> vec;

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    vec.resize(x_size);
    ContentGenerate<T> generator;

    std::generate(vec.begin(), vec.end(), generator);

    {
        // Create a dummy group to annotate with an attribute
        Group g = file.createGroup("dummy_group");

        // check that no attributes are there
        std::size_t n = g.getNumberAttributes();
        BOOST_CHECK_EQUAL(n, 0);

        std::vector<std::string> all_attribute_names = g.listAttributeNames();
        BOOST_CHECK_EQUAL(all_attribute_names.size(), 0);

        bool has_attribute = g.hasAttribute("my_attribute");
        BOOST_CHECK_EQUAL(has_attribute, false);

        Attribute a1 =
            g.createAttribute<T>("my_attribute", DataSpace::From(vec));
        a1.write(vec);

        // check now that we effectively have an attribute listable
        std::size_t n2 = g.getNumberAttributes();
        BOOST_CHECK_EQUAL(n2, 1);

        has_attribute = g.hasAttribute("my_attribute");
        BOOST_CHECK_EQUAL(has_attribute, true);

        all_attribute_names = g.listAttributeNames();
        BOOST_CHECK_EQUAL(all_attribute_names.size(), 1);
        BOOST_CHECK_EQUAL(all_attribute_names[0], std::string("my_attribute"));

        // Create the same attribute on a newly created dataset
        DataSet s =
            g.createDataSet("dummy_dataset", DataSpace(1), AtomicType<int>());

        Attribute a2 =
            s.createAttribute<T>("my_attribute_copy", DataSpace::From(vec));
        a2.write(vec);
    }

    typename std::vector<T> result1, result2;

    {
        Attribute a1_read =
            file.getGroup("dummy_group").getAttribute("my_attribute");
        a1_read.read(result1);

        BOOST_CHECK_EQUAL(vec.size(), x_size);
        BOOST_CHECK_EQUAL(result1.size(), x_size);

        for (size_t i = 0; i < x_size; ++i) {
            // std::cout << result[i] << " " << vec[i] << "  ";
            BOOST_CHECK_EQUAL(result1[i], vec[i]);
        }

        Attribute a2_read = file.getDataSet("/dummy_group/dummy_dataset")
                                .getAttribute("my_attribute_copy");
        a2_read.read(result2);

        BOOST_CHECK_EQUAL(vec.size(), x_size);
        BOOST_CHECK_EQUAL(result2.size(), x_size);

        for (size_t i = 0; i < x_size; ++i) {
            // std::cout << result[i] << " " << vec[i] << "  ";
            BOOST_CHECK_EQUAL(result2[i], vec[i]);
        }
    }
}

BOOST_AUTO_TEST_CASE_TEMPLATE(ReadWriteAttributeVector, T, dataset_test_types) {
    readWriteAttributeVectorTest<T>();
}

template <typename T>
void readWriteVector2DTest() {
    using namespace HighFive;

    std::ostringstream filename;
    filename << "h5_rw_vec_2d_" << typeid(T).name() << "_test.h5";

    const size_t x_size = 10;
    const size_t y_size = 10;
    const std::string DATASET_NAME("dset");
    typename std::vector<std::vector<T> > vec;

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    vec.resize(x_size);
    ContentGenerate<T> generator;

    generate2D(vec, x_size, y_size, generator);

    // Create a dataset with double precision floating points
    DataSet dataset = file.createDataSet<T>(DATASET_NAME, DataSpace::From(vec));

    dataset.write(vec);

    typename std::vector<std::vector<T> > result;

    dataset.read(result);

    BOOST_CHECK_EQUAL(vec.size(), x_size);
    BOOST_CHECK_EQUAL(result.size(), x_size);

    BOOST_CHECK_EQUAL(vec[0].size(), y_size);
    BOOST_CHECK_EQUAL(result[0].size(), y_size);

    for (size_t i = 0; i < x_size; ++i) {
        for (size_t j = 0; i < y_size; ++i) {
            BOOST_CHECK_EQUAL(result[i][j], vec[i][j]);
        }
    }
}

BOOST_AUTO_TEST_CASE_TEMPLATE(readWriteVector2D, T, numerical_test_types) {

    readWriteVector2DTest<T>();
}

#ifdef H5_USE_BOOST

template <typename T>
void MultiArray3DTest() {

    typedef typename boost::multi_array<T, 3> MultiArray;

    std::ostringstream filename;
    filename << "h5_rw_multiarray_" << typeid(T).name() << "_test.h5";

    const size_t size_x = 10, size_y = 10, size_z = 10;
    const std::string DATASET_NAME("dset");
    MultiArray array(boost::extents[size_x][size_y][size_z]);

    ContentGenerate<T> generator;
    std::generate(array.data(), array.data() + array.num_elements(), generator);

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    DataSet dataset =
        file.createDataSet<T>(DATASET_NAME, DataSpace::From(array));

    dataset.write(array);

    // read it back
    MultiArray result;

    dataset.read(result);

    for (size_t i = 0; i < size_x; ++i) {
        for (size_t j = 0; j < size_y; ++j) {
            for (size_t k = 0; k < size_z; ++k) {
                // std::cout << array[i][j][k] << " ";
                BOOST_CHECK_EQUAL(array[i][j][k], result[i][j][k]);
            }
        }
    }
}

BOOST_AUTO_TEST_CASE_TEMPLATE(MultiArray3D, T, numerical_test_types) {

    MultiArray3DTest<T>();
}

template <typename T>
void ublas_matrix_Test() {

    typedef typename boost::numeric::ublas::matrix<T> Matrix;

    std::ostringstream filename;
    filename << "h5_rw_multiarray_" << typeid(T).name() << "_test.h5";

    const size_t size_x = 10, size_y = 10;
    const std::string DATASET_NAME("dset");

    Matrix mat(size_x, size_y);

    ContentGenerate<T> generator;
    for (std::size_t i = 0; i < mat.size1(); ++i) {
        for (std::size_t j = 0; j < mat.size2(); ++j) {
            mat(i, j) = generator();
        }
    }

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    DataSet dataset = file.createDataSet<T>(DATASET_NAME, DataSpace::From(mat));

    dataset.write(mat);

    // read it back
    Matrix result;

    dataset.read(result);

    for (size_t i = 0; i < size_x; ++i) {
        for (size_t j = 0; j < size_y; ++j) {
            // std::cout << array[i][j][k] << " ";
            BOOST_CHECK_EQUAL(mat(i, j), result(i, j));
        }
    }
}

BOOST_AUTO_TEST_CASE_TEMPLATE(ublas_matrix, T, numerical_test_types) {

    ublas_matrix_Test<T>();
}

#endif

template <typename T>
void selectionArraySimpleTest() {

    typedef typename std::vector<T> Vector;

    std::ostringstream filename;
    filename << "h5_rw_select_test_" << typeid(T).name() << "_test.h5";

    const size_t size_x = 10;
    const size_t offset_x = 2, count_x = 5;

    const std::string DATASET_NAME("dset");

    Vector values(size_x);

    ContentGenerate<T> generator;
    std::generate(values.begin(), values.end(), generator);

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    DataSet dataset =
        file.createDataSet<T>(DATASET_NAME, DataSpace::From(values));

    dataset.write(values);

    file.flush();

    // select slice
    {
        // read it back
        Vector result;
        std::vector<size_t> offset;
        offset.push_back(offset_x);
        std::vector<size_t> size;
        size.push_back(count_x);

        Selection slice = dataset.select(offset, size);

        BOOST_CHECK_EQUAL(slice.getSpace().getDimensions()[0], size_x);
        BOOST_CHECK_EQUAL(slice.getMemSpace().getDimensions()[0], count_x);

        slice.read(result);

        BOOST_CHECK_EQUAL(result.size(), 5);

        for (size_t i = 0; i < count_x; ++i) {
            BOOST_CHECK_EQUAL(values[i + offset_x], result[i]);
        }
    }

    // select cherry pick
    {
        // read it back
        Vector result;
        std::vector<size_t> ids;
        ids.push_back(1);
        ids.push_back(3);
        ids.push_back(4);
        ids.push_back(7);

        Selection slice = dataset.select(ElementSet(ids));

        BOOST_CHECK_EQUAL(slice.getSpace().getDimensions()[0], size_x);
        BOOST_CHECK_EQUAL(slice.getMemSpace().getDimensions()[0], ids.size());

        slice.read(result);

        BOOST_CHECK_EQUAL(result.size(), ids.size());

        for (size_t i = 0; i < ids.size(); ++i) {
            const std::size_t id = ids[i];
            BOOST_CHECK_EQUAL(values[id], result[i]);
        }
    }
}

BOOST_AUTO_TEST_CASE_TEMPLATE(selectionArraySimple, T, dataset_test_types) {

    selectionArraySimpleTest<T>();
}

template <typename T>
void columnSelectionTest() {

    std::ostringstream filename;
    filename << "h5_rw_select_column_test_" << typeid(T).name() << "_test.h5";

    const size_t x_size = 10;
    const size_t y_size = 7;

    const std::string DATASET_NAME("dset");

    T values[x_size][y_size];

    ContentGenerate<T> generator;
    generate2D(values, x_size, y_size, generator);

    // Create a new file using the default property lists.
    File file(filename.str(), File::ReadWrite | File::Create | File::Truncate);

    // Create the data space for the dataset.
    std::vector<size_t> dims;
    dims.push_back(x_size);
    dims.push_back(y_size);

    DataSpace dataspace(dims);
    // Create a dataset with arbitrary type
    DataSet dataset = file.createDataSet<T>(DATASET_NAME, dataspace);

    dataset.write(values);

    file.flush();

    std::vector<size_t> columns;
    columns.push_back(1);
    columns.push_back(3);
    columns.push_back(5);

    Selection slice = dataset.select(columns);
    T result[x_size][3];
    slice.read(result);

    BOOST_CHECK_EQUAL(slice.getSpace().getDimensions()[0], x_size);
    BOOST_CHECK_EQUAL(slice.getMemSpace().getDimensions()[0], x_size);

    for (size_t i = 0; i < 3; ++i)
        for (size_t j = 0; j < x_size; ++j)
            BOOST_CHECK_EQUAL(result[j][i], values[j][columns[i]]);
}

BOOST_AUTO_TEST_CASE_TEMPLATE(columnSelection, T, numerical_test_types) {

    columnSelectionTest<T>();
}

template <typename T>
void attribute_scalar_rw() {

    std::ostringstream filename;
    filename << "h5_rw_attribute_scalar_rw" << typeid(T).name() << "_test.h5";

    File h5file(filename.str(),
                File::ReadWrite | File::Create | File::Truncate);

    ContentGenerate<T> generator;

    const T attribute_value(generator());

    Group g = h5file.createGroup("metadata");

    bool family_exist = g.hasAttribute("family");
    BOOST_CHECK_EQUAL(family_exist, false);

    // write a scalar attribute
    {
        T out(attribute_value);
        Attribute att = g.createAttribute<T>("family", DataSpace::From(out));
        att.write(out);
    }

    h5file.flush();

    // test if attribute exist
    family_exist = g.hasAttribute("family");
    BOOST_CHECK_EQUAL(family_exist, true);

    // read back a scalar attribute
    {
        T res;
        Attribute att = g.getAttribute("family");
        att.read(res);
        BOOST_CHECK_EQUAL(res, attribute_value);
    }
}

BOOST_AUTO_TEST_CASE_TEMPLATE(attribute_scalar_rw_all, T, dataset_test_types) {
    attribute_scalar_rw<T>();
}


text:
//
// experimental/impl/redirect_error.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP
#define BOOST_ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/variadic_templates.hpp>
#include <boost/asio/handler_type.hpp>
#include <boost/system/system_error.hpp>

#include <boost/asio/detail/push_options.hpp>

namespace boost {
namespace asio {
namespace experimental {
namespace detail {

// Class to adapt a redirect_error_t as a completion handler.
template <typename Handler>
class redirect_error_handler
{
public:
  template <typename CompletionToken>
  redirect_error_handler(redirect_error_t<CompletionToken> e)
    : ec_(e.ec_),
      handler_(BOOST_ASIO_MOVE_CAST(CompletionToken)(e.token_))
  {
  }

#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)

  template <typename... Args>
  void operator()(BOOST_ASIO_MOVE_ARG(Args)... args)
  {
    handler_(BOOST_ASIO_MOVE_CAST(Args)(args)...);
  }

  template <typename... Args>
  void operator()(const boost::system::error_code& ec,
      BOOST_ASIO_MOVE_ARG(Args)... args)
  {
    ec_ = ec;
    handler_(BOOST_ASIO_MOVE_CAST(Args)(args)...);
  }

#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)

  void operator()()
  {
    handler_();
  }

  void operator()(const boost::system::error_code& ec)
  {
    ec_ = ec;
    handler_();
  }

#define BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
  template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \
  { \
    handler_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
  } \
  \
  template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  void operator()(const boost::system::error_code& ec, \
      BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \
  { \
    ec_ = ec; \
    handler_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
  } \
  /**/
  BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF)
#undef BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF

#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)

//private:
  boost::system::error_code& ec_;
  Handler handler_;
};

template <typename Handler>
inline void* asio_handler_allocate(std::size_t size,
    redirect_error_handler<Handler>* this_handler)
{
  return boost_asio_handler_alloc_helpers::allocate(
      size, this_handler->handler_);
}

template <typename Handler>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
    redirect_error_handler<Handler>* this_handler)
{
  boost_asio_handler_alloc_helpers::deallocate(
      pointer, size, this_handler->handler_);
}

template <typename Handler>
inline bool asio_handler_is_continuation(
    redirect_error_handler<Handler>* this_handler)
{
  return boost_asio_handler_cont_helpers::is_continuation(
        this_handler->handler_);
}

template <typename Function, typename Handler>
inline void asio_handler_invoke(Function& function,
    redirect_error_handler<Handler>* this_handler)
{
  boost_asio_handler_invoke_helpers::invoke(
      function, this_handler->handler_);
}

template <typename Function, typename Handler>
inline void asio_handler_invoke(const Function& function,
    redirect_error_handler<Handler>* this_handler)
{
  boost_asio_handler_invoke_helpers::invoke(
      function, this_handler->handler_);
}

template <typename Signature>
struct redirect_error_signature
{
  typedef Signature type;
};

#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)

template <typename R, typename... Args>
struct redirect_error_signature<R(boost::system::error_code, Args...)>
{
  typedef R type(Args...);
};

template <typename R, typename... Args>
struct redirect_error_signature<R(const boost::system::error_code&, Args...)>
{
  typedef R type(Args...);
};

#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)

template <typename R>
struct redirect_error_signature<R(boost::system::error_code)>
{
  typedef R type();
};

template <typename R>
struct redirect_error_signature<R(const boost::system::error_code&)>
{
  typedef R type();
};

#define BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \
  template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  struct redirect_error_signature< \
      R(boost::system::error_code, BOOST_ASIO_VARIADIC_TARGS(n))> \
  { \
    typedef R type(BOOST_ASIO_VARIADIC_TARGS(n)); \
  }; \
  \
  template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  struct redirect_error_signature< \
      R(const boost::system::error_code&, BOOST_ASIO_VARIADIC_TARGS(n))> \
  { \
    typedef R type(BOOST_ASIO_VARIADIC_TARGS(n)); \
  }; \
  /**/
  BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF)
#undef BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF

#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)

} // namespace detail
} // namespace experimental

#if !defined(GENERATING_DOCUMENTATION)

template <typename CompletionToken, typename Signature>
struct async_result<experimental::redirect_error_t<CompletionToken>, Signature>
  : async_result<CompletionToken,
      typename experimental::detail::redirect_error_signature<Signature>::type>
{
  typedef experimental::detail::redirect_error_handler<
    typename async_result<CompletionToken,
      typename experimental::detail::redirect_error_signature<Signature>::type>
        ::completion_handler_type> completion_handler_type;

  explicit async_result(completion_handler_type& h)
    : async_result<CompletionToken,
        typename experimental::detail::redirect_error_signature<
          Signature>::type>(h.handler_)
  {
  }
};

#if !defined(BOOST_ASIO_NO_DEPRECATED)

template <typename CompletionToken, typename Signature>
struct handler_type<experimental::redirect_error_t<CompletionToken>, Signature>
{
  typedef experimental::detail::redirect_error_handler<
    typename async_result<CompletionToken,
      typename experimental::detail::redirect_error_signature<Signature>::type>
        ::completion_handler_type> type;
};

template <typename Handler>
struct async_result<experimental::detail::redirect_error_handler<Handler> >
  : async_result<Handler>
{
  explicit async_result(
      experimental::detail::redirect_error_handler<Handler>& h)
    : async_result<Handler>(h.handler_)
  {
  }
};

#endif // !defined(BOOST_ASIO_NO_DEPRECATED)

template <typename Handler, typename Executor>
struct associated_executor<
    experimental::detail::redirect_error_handler<Handler>, Executor>
{
  typedef typename associated_executor<Handler, Executor>::type type;

  static type get(
      const experimental::detail::redirect_error_handler<Handler>& h,
      const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
  {
    return associated_executor<Handler, Executor>::get(h.handler_, ex);
  }
};

template <typename Handler, typename Allocator>
struct associated_allocator<
    experimental::detail::redirect_error_handler<Handler>, Allocator>
{
  typedef typename associated_allocator<Handler, Allocator>::type type;

  static type get(
      const experimental::detail::redirect_error_handler<Handler>& h,
      const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
  {
    return associated_allocator<Handler, Allocator>::get(h.handler_, a);
  }
};

#endif // !defined(GENERATING_DOCUMENTATION)

} // namespace asio
} // namespace boost

#include <boost/asio/detail/pop_options.hpp>

#endif // BOOST_ASIO_EXPERIMENTAL_IMPL_REDIRECT_ERROR_HPP