<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#pragma once
#include "ork/memory.hpp"
#include "ork/private/text_includes.hpp"
#include "ork/string_utils.hpp"
#include "ork/type_traits.hpp"

#include "glm/fwd.hpp"

namespace ork {

#define ORK_OI_DECL_(SUFFIX) \
    class ORK_ORK_API exportable { \
    public: \
        virtual ~exportable() {} \
\
    public: \
        virtual void ORK_CAT(to_, SUFFIX)(node&) const = 0; \
    }; \
    class ORK_ORK_API importable { \
    public: \
        virtual ~importable() {} \
\
    public: \
        virtual void ORK_CAT(from_, SUFFIX)(const node&) = 0; \
    }; \
    class ORK_ORK_API serializable \
        : public exportable \
        , public importable { \
    public: \
        virtual ~serializable() {} \
    };

namespace json {

#if ORK_USE_JSON

using node = Json::Value;
ORK_OI_DECL_(json)

ORK_ORK_EXT(void)
export_file(const string& path_to_file, const node& root);
ORK_ORK_EXT(void)
export_file(const string& path_to_file, const exportable& object);
ORK_ORK_EXT(void) load_and_parse(bi_stream& fin, node& root);
ORK_ORK_EXT(node) load_and_parse(bi_stream& fin);

#endif // ORK_USE_JSON

} // namespace json
namespace xml {

#if ORK_USE_PUGI

using node = pugi::xml_node;
ORK_OI_DECL_(xml)

ORK_ORK_EXT(void)
export_file(const string& path_to_file, const exportable& object, const bstring& root_node_name);
ORK_ORK_EXT(void)
export_file_permissive(const string& path_to_file, const bstring& root_tag, const exportable& object);
ORK_ORK_EXT(void)
load_and_parse(bi_stream& fin, pugi::xml_document& root); // Just create a file with error checking
ORK_ORK_EXT(void)
load_and_parse_permissive(const file::path& path_to_file, const bstring& root_tag, serializable& obj);

/*
These are permissive interfaces
*/
template<typename T>
void value_to_attribute(node& node, const bstring& tag, ORK_CPARAM_T value)
{
    try {
        node.append_attribute(tag.c_str()).set_value(to_bstring(value).c_str());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to set attribute ") << ORK_BYTE_2_STR(node.name())
            << ORK(":") << ORK_BYTE_2_STR(tag) << ORK(", ") << e.what();
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened setting attribute ")
            << ORK_BYTE_2_STR(node.name()) << ORK(":") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_to_xml(node& node, const bstring& tag, ORK_CPARAM_T value)
{
    try {
        node.append_child(tag.c_str())
            .append_child(pugi::node_pcdata)
            .set_value(to_bstring(value).c_str());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to set tag ") << ORK_BYTE_2_STR(tag) << ORK(": ")
            << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened setting tag ") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_to_xml(node& node, ORK_CPARAM_T value)
{
    try {
        node.append_child(pugi::node_pcdata).set_value(to_bstring(value).c_str());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to set tag ") << ORK_BYTE_2_STR(node.name())
            << ORK(": ") << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error) << ORK("Something happened setting tag ")
                                       << ORK_BYTE_2_STR(node.name());
    }
}

template<typename T>
void value_from_attribute(const node& node, const bstring& tag, ORK_REF_T value)
{
    try {
        value = from_string<ORK_VAL_T>(node.attribute(tag.c_str()).value());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to read parameter ") << ORK_BYTE_2_STR(tag)
            << ORK(": ") << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened reading parameter ") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_from_xml(const node& node, const bstring& tag, ORK_REF_T value)
{
    try {
        value = from_string<ORK_VAL_T>(node.child_value(tag.c_str()));
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to read tag ") << ORK_BYTE_2_STR(tag) << ORK(": ")
            << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened reading tag ") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_from_xml(const node& node, ORK_REF_T value)
{
    try {
        value = from_string<ORK_VAL_T>(node.child_value());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to read tag ") << ORK_BYTE_2_STR(node.name())
            << ORK(": ") << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error) << ORK("Something happened reading tag ")
                                       << ORK_BYTE_2_STR(node.name());
    }
}

// Overloads to eliminate dependency definitions
#    define ORK_XML_SERIALIZE_DECL_(API, TYPE) \
        API(void) \
        to_xml(ork::xml::node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value); \
        API(void) \
        to_attribute( \
            ork::xml::node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value); \
        API(void) \
        from_xml(const ork::xml::node& node, const ork::bstring& tag, ORK_REF(TYPE) value); \
        API(void) \
        from_attribute( \
            const ork::xml::node& node, const ork::bstring& tag, ORK_REF(TYPE) value)

#    define ORK_XML_SERIALIZE_DECL(TYPE) ORK_XML_SERIALIZE_DECL_(ORK_EXT, TYPE)
#    define ORK_ORK_XML_SERIALIZE_DECL(TYPE) \
        ORK_XML_SERIALIZE_DECL_(ORK_ORK_EXT, TYPE)

ORK_ORK_XML_SERIALIZE_DECL(int);
ORK_ORK_XML_SERIALIZE_DECL(unsigned);
ORK_ORK_XML_SERIALIZE_DECL(size_t);
ORK_ORK_XML_SERIALIZE_DECL(float);
ORK_ORK_XML_SERIALIZE_DECL(double);
ORK_ORK_XML_SERIALIZE_DECL(bstring);
ORK_ORK_XML_SERIALIZE_DECL(wstring);

#    define ORK_XML_SERIALIZE_DEF(TYPE) \
        void to_xml(node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value) \
        { \
            ork::xml::value_to_xml<TYPE>(node, tag, value); \
        } \
        void to_attribute(node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value) \
        { \
            ork::xml::value_to_attribute<TYPE>(node, tag, value); \
        } \
        void from_xml(const node& node, const ork::bstring& tag, ORK_REF(TYPE) value) \
        { \
            ork::xml::value_from_xml<TYPE>(node, tag, value); \
        } \
        void from_attribute( \
            const node& node, const ork::bstring& tag, ORK_REF(TYPE) value) \
        { \
            ork::xml::value_from_xml<TYPE>(node, tag, value); \
        }

#endif // ORK_USE_PUGI

} // namespace xml
namespace yaml {

#if ORK_USE_YAML

using node = YAML::Node;
ORK_OI_DECL_(yaml)

ORK_ORK_EXT(void)
export_file(const string& path_to_file, const node& root);
ORK_ORK_EXT(void)
export_file(const string& path_to_file, const exportable& object);
ORK_ORK_EXT(void) load_and_parse(bi_stream& fin, node& root);
ORK_ORK_EXT(node) load_and_parse(bi_stream& fin);

#endif // ORK_USE_YAML

} // namespace yaml
} // namespace ork
<commit_msg>Added a tagged base class<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#pragma once
#include "ork/memory.hpp"
#include "ork/private/text_includes.hpp"
#include "ork/string_utils.hpp"
#include "ork/type_traits.hpp"

#include "glm/fwd.hpp"

namespace ork {

// Serialization tag: basis for a child node
struct tagged {
private:
    ork::bstring _tag;

public:
    ORK_INLINE tagged(const ork::bstring& tag)
        : _tag{tag}
    {}
    ORK_MOVEABLE(tagged);

public:
    ORK_INLINE const ork::bstring& tag() const
    {
        return _tag;
    }
};

#define ORK_OI_DECL_(SUFFIX) \
    class ORK_ORK_API exportable { \
    public: \
        virtual ~exportable() {} \
\
    public: \
        virtual void ORK_CAT(to_, SUFFIX)(node&) const = 0; \
    }; \
    class ORK_ORK_API importable { \
    public: \
        virtual ~importable() {} \
\
    public: \
        virtual void ORK_CAT(from_, SUFFIX)(const node&) = 0; \
    }; \
    class ORK_ORK_API serializable \
        : public exportable \
        , public importable { \
    public: \
        virtual ~serializable() {} \
    };

namespace json {

#if ORK_USE_JSON

using node = Json::Value;
ORK_OI_DECL_(json)

ORK_ORK_EXT(void)
export_file(const string& path_to_file, const node& root);
ORK_ORK_EXT(void)
export_file(const string& path_to_file, const exportable& object);
ORK_ORK_EXT(void) load_and_parse(bi_stream& fin, node& root);
ORK_ORK_EXT(node) load_and_parse(bi_stream& fin);

#endif // ORK_USE_JSON

} // namespace json
namespace xml {

#if ORK_USE_PUGI

using node = pugi::xml_node;
ORK_OI_DECL_(xml)

ORK_ORK_EXT(void)
export_file(const string& path_to_file, const exportable& object, const bstring& root_node_name);
ORK_ORK_EXT(void)
export_file_permissive(const string& path_to_file, const bstring& root_tag, const exportable& object);
ORK_ORK_EXT(void)
load_and_parse(bi_stream& fin, pugi::xml_document& root); // Just create a file with error checking
ORK_ORK_EXT(void)
load_and_parse_permissive(const file::path& path_to_file, const bstring& root_tag, serializable& obj);

/*
These are permissive interfaces
*/
template<typename T>
void value_to_attribute(node& node, const bstring& tag, ORK_CPARAM_T value)
{
    try {
        node.append_attribute(tag.c_str()).set_value(to_bstring(value).c_str());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to set attribute ") << ORK_BYTE_2_STR(node.name())
            << ORK(":") << ORK_BYTE_2_STR(tag) << ORK(", ") << e.what();
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened setting attribute ")
            << ORK_BYTE_2_STR(node.name()) << ORK(":") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_to_xml(node& node, const bstring& tag, ORK_CPARAM_T value)
{
    try {
        node.append_child(tag.c_str())
            .append_child(pugi::node_pcdata)
            .set_value(to_bstring(value).c_str());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to set tag ") << ORK_BYTE_2_STR(tag) << ORK(": ")
            << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened setting tag ") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_to_xml(node& node, ORK_CPARAM_T value)
{
    try {
        node.append_child(pugi::node_pcdata).set_value(to_bstring(value).c_str());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to set tag ") << ORK_BYTE_2_STR(node.name())
            << ORK(": ") << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error) << ORK("Something happened setting tag ")
                                       << ORK_BYTE_2_STR(node.name());
    }
}

template<typename T>
void value_from_attribute(const node& node, const bstring& tag, ORK_REF_T value)
{
    try {
        value = from_string<ORK_VAL_T>(node.attribute(tag.c_str()).value());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to read parameter ") << ORK_BYTE_2_STR(tag)
            << ORK(": ") << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened reading parameter ") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_from_xml(const node& node, const bstring& tag, ORK_REF_T value)
{
    try {
        value = from_string<ORK_VAL_T>(node.child_value(tag.c_str()));
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to read tag ") << ORK_BYTE_2_STR(tag) << ORK(": ")
            << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error)
            << ORK("Something happened reading tag ") << ORK_BYTE_2_STR(tag);
    }
}
template<typename T>
void value_from_xml(const node& node, ORK_REF_T value)
{
    try {
        value = from_string<ORK_VAL_T>(node.child_value());
    }
    catch(std::exception& e) {
        ORK_LOG(severity_level::error)
            << ORK("Failed to read tag ") << ORK_BYTE_2_STR(node.name())
            << ORK(": ") << ORK_BYTE_2_STR(e.what());
    }
    catch(...) {
        ORK_LOG(severity_level::error) << ORK("Something happened reading tag ")
                                       << ORK_BYTE_2_STR(node.name());
    }
}

// Overloads to eliminate dependency definitions
#    define ORK_XML_SERIALIZE_DECL_(API, TYPE) \
        API(void) \
        to_xml(ork::xml::node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value); \
        API(void) \
        to_attribute( \
            ork::xml::node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value); \
        API(void) \
        from_xml(const ork::xml::node& node, const ork::bstring& tag, ORK_REF(TYPE) value); \
        API(void) \
        from_attribute( \
            const ork::xml::node& node, const ork::bstring& tag, ORK_REF(TYPE) value)

#    define ORK_XML_SERIALIZE_DECL(TYPE) ORK_XML_SERIALIZE_DECL_(ORK_EXT, TYPE)
#    define ORK_ORK_XML_SERIALIZE_DECL(TYPE) \
        ORK_XML_SERIALIZE_DECL_(ORK_ORK_EXT, TYPE)

ORK_ORK_XML_SERIALIZE_DECL(int);
ORK_ORK_XML_SERIALIZE_DECL(unsigned);
ORK_ORK_XML_SERIALIZE_DECL(size_t);
ORK_ORK_XML_SERIALIZE_DECL(float);
ORK_ORK_XML_SERIALIZE_DECL(double);
ORK_ORK_XML_SERIALIZE_DECL(bstring);
ORK_ORK_XML_SERIALIZE_DECL(wstring);

#    define ORK_XML_SERIALIZE_DEF(TYPE) \
        void to_xml(node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value) \
        { \
            ork::xml::value_to_xml<TYPE>(node, tag, value); \
        } \
        void to_attribute(node& node, const ork::bstring& tag, ORK_CPARAM(TYPE) value) \
        { \
            ork::xml::value_to_attribute<TYPE>(node, tag, value); \
        } \
        void from_xml(const node& node, const ork::bstring& tag, ORK_REF(TYPE) value) \
        { \
            ork::xml::value_from_xml<TYPE>(node, tag, value); \
        } \
        void from_attribute( \
            const node& node, const ork::bstring& tag, ORK_REF(TYPE) value) \
        { \
            ork::xml::value_from_xml<TYPE>(node, tag, value); \
        }

#endif // ORK_USE_PUGI

} // namespace xml
namespace yaml {

#if ORK_USE_YAML

using node = YAML::Node;
ORK_OI_DECL_(yaml)

ORK_ORK_EXT(void)
export_file(const string& path_to_file, const node& root);
ORK_ORK_EXT(void)
export_file(const string& path_to_file, const exportable& object);
ORK_ORK_EXT(void) load_and_parse(bi_stream& fin, node& root);
ORK_ORK_EXT(node) load_and_parse(bi_stream& fin);

#endif // ORK_USE_YAML

} // namespace yaml
} // namespace ork
<|endoftext|>


<commit_before><commit_msg>coverity#738935 Unitialized scalar field<commit_after><|endoftext|>


<commit_before>/*! \file
 *
 * \brief A map of spin and spatial symmetry to data types
 * \author Benjamin Pritchard (ben@bennyp.org)
 */

#ifndef PULSAR_GUARD_MATH__BLOCKBYIRREPSPIN_HPP_
#define PULSAR_GUARD_MATH__BLOCKBYIRREPSPIN_HPP_

#include <map>
#include <iostream>
#include "pulsar/util/Serialization.hpp"
#include "pulsar/exception/Exceptions.hpp"
#include "pulsar/math/Irrep.hpp"

#include "bphash/types/map.hpp"

namespace pulsar{
namespace math{

/* \brief Maps spin and spatial symmetry to data
 *
 * \par Hashing
 *     The hash value is unique with respect to the map between
 *     the irrep/spatial symmetry and the hashing of data type \p T.
 *     See that class for details.
 */
template<typename T>
class BlockByIrrepSpin
{
    public:
        typedef typename std::map<int, T> SpinMap;
        typedef typename std::map<Irrep, SpinMap> IrrepSpinMap;

        typedef typename IrrepSpinMap::iterator iterator;
        typedef typename IrrepSpinMap::const_iterator const_iterator;

        //! \todo cannot be default due to some compiler issues
        BlockByIrrepSpin() {};
        BlockByIrrepSpin(const BlockByIrrepSpin & rhs) : data_(rhs.data_) { }
        BlockByIrrepSpin(BlockByIrrepSpin && rhs) : data_(std::move(rhs.data_)) { }

        BlockByIrrepSpin & operator=(const BlockByIrrepSpin &) = default;
        BlockByIrrepSpin & operator=(BlockByIrrepSpin &&) = default;

        bool operator==(const BlockByIrrepSpin & rhs) const
        {
            return data_ == rhs.data_;
        }

        bool operator!=(const BlockByIrrepSpin & rhs) const
        {
            return !((*this) == rhs);
        }

        bool has(Irrep irrep, int spin) const
        {
            if(data_.count(irrep))
                return data_.at(irrep).count(spin);
            else
                return 0;
        }

        std::set<Irrep> get_irreps(void) const
        {
            std::set<Irrep> ret;
            for(const auto & it : data_)
                ret.insert(it.first);
            return ret;
        }

        std::set<int> get_spins(Irrep irrep) const
        {
            std::set<int> ret;
            if(data_.count(irrep))
            {
                for(const auto & it : data_.at(irrep))
                    ret.insert(it.first);
            }
            return ret;
        }

        T & get(Irrep irrep, int spin)
        {
            //! \todo need irrep to string
            //if(!HasMatrix(irrep, spin))
            //    throw exception::MathException("No matrix with this irrep/spin",
            //                                   "irrep", irrep, "spin", spin);

            return data_.at(irrep).at(spin);
        }

        const T & get(Irrep irrep, int spin) const
        {
            //! \todo need irrep to string
            //if(!HasMatrix(irrep, spin))
            //    throw exception::MathException("No matrix with this irrep/spin",
            //                                   "irrep", irrep, "spin", spin);

            return data_.at(irrep).at(spin);
        }

        void set(Irrep irrep, int spin, const T & val)
        {
            if(data_.count(irrep) == 0)
            {
                // will create a new SpinMap
                data_[irrep].emplace(spin, val);
            }
            else
            {
                if(data_.at(irrep).count(spin))
                    data_[irrep].erase(spin);  // avoid operator=

                data_.at(irrep).emplace(spin, val);
            }
        }

        void set(Irrep irrep, int spin, T && val)
        {
            if(data_.count(irrep) == 0)
            {
                // will create a new SpinMap
                data_[irrep].emplace(spin, std::move(val));
            }
            else
            {
                if(data_.at(irrep).count(spin))
                    data_[irrep].erase(spin);  // avoid operator=

                data_.at(irrep).emplace(spin, std::move(val));
            }
        }

        iterator begin(void) { return data_.begin(); }

        const_iterator begin(void) const { return data_.begin(); }

        iterator end(void) { return data_.end(); }

        const_iterator end(void) const { return data_.end(); }

        //! Does this object have same irrep/spin structure as another
        template<typename U>
        bool same_structure(const BlockByIrrepSpin<U> & rhs) const
        {
            for(const auto & irrepit : *this)
            for(const auto & spinit : irrepit.second)
            {
                if(!rhs.has(irrepit.first, spinit.first))
                    return false;
            }

            for(const auto & irrepit : rhs)
            for(const auto & spinit : irrepit.second)
            {
                if(!has(irrepit.first, spinit.first))
                    return false;
            }

            return true;
        }

        /*! \brief Obtain a hash of the data
         *
         * Details depend on what kind of data is stored.
         * See the hashing functions of the stored type
         * for details.
         */
        bphash::HashValue my_hash(void) const
        {
            return bphash::make_hash(bphash::HashType::Hash128, *this);
        }

        ///Prints the tensor by passing underlying tensor type to ostream
        std::ostream& print(std::ostream& os)const;

    private:
        IrrepSpinMap data_;

        //! \name Serialization
        ///@{

        DECLARE_SERIALIZATION_FRIENDS
        friend class bphash::Hasher;

        template<class Archive>
        void serialize(Archive & ar)
        {
            ar(data_);
        }

        void hash(bphash::Hasher & h) const
        {
            h(data_);
        }

        ///@}
};

///Helper function that determines if this data is for a restricted computation
template<typename T>
bool is_restricted(const T& Tensor){
    for(const auto& irr: Tensor)
    {

        if(irr.second.size()!=2 ||  //Only two spins
           !irr.second.count(Spin::alpha) ||  //One is alpha...
           !irr.second.count(Spin::beta)  ||  //...other is beta
           irr.second.at(Spin::alpha)!=irr.second.at(Spin::beta) //literally same
           )return false;
    }
    return true;
}

template<typename T>
std::ostream& BlockByIrrepSpin<T>::print(std::ostream& os)const
{
    for(const auto& irr: data_)
    {
        if(is_restricted(*this))
            os<<irrep_to_string.at(irr.first)<<" alpha==beta"<<std::endl
              <<irr.second.at(Spin::alpha)<<std::endl;
        else
        {
            for(const typename SpinMap::value_type& spin: irr.second)
               os<<irrep_to_string.at(irr.first)<<" "<<spin.first
                 <<" "<<std::endl<<spin.second<<std::endl;
        }
    }
    return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os,const BlockByIrrepSpin<T>& tensor)
{
    return tensor.print(os);
}

} // close namespace math
} // close namespace pulsar

#endif
<commit_msg>BlockByIrrepSpin consistent with standard in PR<commit_after>/*! \file
 *
 * \brief A map of spin and spatial symmetry to data types
 * \author Benjamin Pritchard (ben@bennyp.org)
 */

#ifndef PULSAR_GUARD_MATH__BLOCKBYIRREPSPIN_HPP_
#define PULSAR_GUARD_MATH__BLOCKBYIRREPSPIN_HPP_

#include <map>
#include <iostream>
#include "pulsar/util/Serialization.hpp"
#include "pulsar/exception/Exceptions.hpp"
#include "pulsar/math/Irrep.hpp"

#include "bphash/types/map.hpp"

namespace pulsar{
namespace math{

/* \brief Maps spin and spatial symmetry to data
 *
 * \par Hashing
 *     The hash value is unique with respect to the map between
 *     the irrep/spatial symmetry and the hashing of data type \p T.
 *     See that class for details.
 */
template<typename T>
class BlockByIrrepSpin
{
    public:
        typedef typename std::map<int, T> SpinMap;
        typedef typename std::map<Irrep, SpinMap> IrrepSpinMap;

        typedef typename IrrepSpinMap::iterator iterator;
        typedef typename IrrepSpinMap::const_iterator const_iterator;

        //! \todo cannot be default due to some compiler issues
        BlockByIrrepSpin() {};
        BlockByIrrepSpin(const BlockByIrrepSpin & rhs) : data_(rhs.data_) { }
        BlockByIrrepSpin(BlockByIrrepSpin && rhs) : data_(std::move(rhs.data_)) { }

        BlockByIrrepSpin & operator=(const BlockByIrrepSpin &) = default;
        BlockByIrrepSpin & operator=(BlockByIrrepSpin &&) = default;

        bool operator==(const BlockByIrrepSpin & rhs) const
        {
            return data_ == rhs.data_;
        }

        bool operator!=(const BlockByIrrepSpin & rhs) const
        {
            return !((*this) == rhs);
        }

        bool has(Irrep irrep, int spin) const
        {
            if(data_.count(irrep))
                return data_.at(irrep).count(spin);
            else
                return 0;
        }

        std::set<Irrep> get_irreps(void) const
        {
            std::set<Irrep> ret;
            for(const auto & it : data_)
                ret.insert(it.first);
            return ret;
        }

        std::set<int> get_spins(Irrep irrep) const
        {
            std::set<int> ret;
            if(data_.count(irrep))
            {
                for(const auto & it : data_.at(irrep))
                    ret.insert(it.first);
            }
            return ret;
        }

        T & get(Irrep irrep, int spin)
        {
            //! \todo need irrep to string
            //if(!HasMatrix(irrep, spin))
            //    throw exception::MathException("No matrix with this irrep/spin",
            //                                   "irrep", irrep, "spin", spin);

            return data_.at(irrep).at(spin);
        }

        const T & get(Irrep irrep, int spin) const
        {
            //! \todo need irrep to string
            //if(!HasMatrix(irrep, spin))
            //    throw exception::MathException("No matrix with this irrep/spin",
            //                                   "irrep", irrep, "spin", spin);

            return data_.at(irrep).at(spin);
        }

        void set(Irrep irrep, int spin, const T & val)
        {
            if(data_.count(irrep) == 0)
            {
                // will create a new SpinMap
                data_[irrep].emplace(spin, val);
            }
            else
            {
                if(data_.at(irrep).count(spin))
                    data_[irrep].erase(spin);  // avoid operator=

                data_.at(irrep).emplace(spin, val);
            }
        }

        void set(Irrep irrep, int spin, T && val)
        {
            if(data_.count(irrep) == 0)
            {
                // will create a new SpinMap
                data_[irrep].emplace(spin, std::move(val));
            }
            else
            {
                if(data_.at(irrep).count(spin))
                    data_[irrep].erase(spin);  // avoid operator=

                data_.at(irrep).emplace(spin, std::move(val));
            }
        }

        iterator begin(void) { return data_.begin(); }

        const_iterator begin(void) const { return data_.begin(); }

        iterator end(void) { return data_.end(); }

        const_iterator end(void) const { return data_.end(); }

        //! Does this object have same irrep/spin structure as another
        template<typename U>
        bool same_structure(const BlockByIrrepSpin<U> & rhs) const
        {
            for(const auto & irrepit : *this)
            for(const auto & spinit : irrepit.second)
            {
                if(!rhs.has(irrepit.first, spinit.first))
                    return false;
            }

            for(const auto & irrepit : rhs)
            for(const auto & spinit : irrepit.second)
            {
                if(!has(irrepit.first, spinit.first))
                    return false;
            }

            return true;
        }

        /*! \brief Obtain a hash of the data
         *
         * Details depend on what kind of data is stored.
         * See the hashing functions of the stored type
         * for details.
         */
        bphash::HashValue my_hash(void) const
        {
            return bphash::make_hash(bphash::HashType::Hash128, *this);
        }

        ///Prints the tensor by passing underlying tensor type to ostream
        std::ostream& print(std::ostream& os)const;

    private:
        IrrepSpinMap data_;

        //! \name Serialization
        ///@{

        DECLARE_SERIALIZATION_FRIENDS
        friend class bphash::Hasher;

        template<class Archive>
        void serialize(Archive & ar)
        {
            ar(data_);
        }

        void hash(bphash::Hasher & h) const
        {
            h(data_);
        }

        ///@}
};

template<typename T>
std::ostream& BlockByIrrepSpin<T>::print(std::ostream& os)const
{
    for(const auto& irr: data_)
    {
        for(const typename SpinMap::value_type& spin: irr.second)
            os<<irrep_to_string.at(irr.first)<<" "<<spin.first
              <<" "<<std::endl<<spin.second<<std::endl;
    }
    return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os,const BlockByIrrepSpin<T>& tensor)
{
    return tensor.print(os);
}

} // close namespace math
} // close namespace pulsar

#endif
<|endoftext|>


<commit_before>/* Copyright (c) 2014 Scott Kuhl. All rights reserved.
 * License: This code is licensed under a 3-clause BSD license. See
 * the file named "LICENSE" for a full copy of the license.
 */

/** @file
 * @author Scott Kuhl
 */
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <string>

#ifndef MISSING_VRPN
#include <vrpn_Tracker.h>
#include <quat.h>
#endif

#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif

#include "kuhl-util.h"
#include "vecmat.h"

#ifndef MISSING_VRPN

/** A mapping of object\@tracker strings to vrpn_Tracker_Remote objects
 * so we can quickly find the appropriate object given an
 * object\@tracker string. */
std::map<std::string, vrpn_Tracker_Remote*> nameToTracker;
/** A mapping of object\@tracker strings to the data that the callback
 * functions store the data into. */
std::map<std::string, vrpn_TRACKERCB> nameToCallbackData;

/** A callback function that will get called whenever the tracked
 * point moves. */
static void VRPN_CALLBACK handle_tracker(void *name, const vrpn_TRACKERCB t)
{
	// Store the data in our map so that someone can use it later.
	std::string s = (char*)name;
	nameToCallbackData[s] = t;
}

#endif

extern "C" {
/** Uses the VRPN library to get the position and orientation of a
 * tracked object.
 *
 * @param object The name of the object being tracked.
 *
 * @param hostname The IP address or hostname of the VRPN server or
 * tracking system computer. If hostname is set to NULL, the IP
 * address of the Vicon tracker in the IVS lab is used.
 *
 * @param pos An array to be filled in with the position information
 * for the tracked object. If we are unable to track the object, a
 * message may be printed and pos will be set to a fixed value.
 *
 * @param orient An array to be filled in with the orientation matrix
 * for the tracked object. The orientation matrix is in row-major
 * order can be used with OpenGL. If the tracking system is moving an
 * object around on the screen, this matrix can be used directly. If
 * the tracking system is moving the OpenGL camera, this matrix may
 * need to be inverted. If we are unable to track the object, a
 * message may be printed and orient will be set to the identity
 * matrix.
 *
 * @return 1 if we returned data from the tracker. 0 if there was
 * problems connecting to the tracker.
 */
int vrpn_get(const char *object, const char *hostname, float pos[3], float orient[16])
{
	/* Set to default values */
	vec3f_set(pos, 10000,10000,10000);
	mat4f_identity(orient);
#ifdef MISSING_VRPN
	printf("You are missing VRPN support.\n");
	return 0;
#else
	/* Construct an object@hostname string. */
	std::string hostnamecpp;
	std::string objectcpp;
	if(hostname == NULL)
	{
		/* Try reading VRPN server information from ~/.vrpn-server

		   This file should contain a single line that says something like:
		   tcp://VRPN.SERVER.IP.ADDR
		 */
		const char *homedir = getenv("HOME");
		char path[1024];
		snprintf(path, 1024, "%s/.vrpn-server", homedir);
		FILE *f = fopen(path, "r");
		if(f == NULL)
		{
			printf("%s: Can't open file %s to get VRPN server information.\n", __func__, path);
			exit(EXIT_FAILURE);
		}
		char vrpnString[1024];
		if(fscanf(f, "%1023s", vrpnString) != 1)
		{
			printf("%s: Can't read %s to get VRPN server information.\n", __func__, path);
			exit(EXIT_FAILURE);
		}
		// printf("%s: Found in %s: %s\n", __func__, path, vrpnString);
		hostnamecpp = vrpnString;
		exit(EXIT_FAILURE);
	}

	objectcpp = object;
	std::string fullname = objectcpp + "@" + hostnamecpp;

	/* Check if we have a tracker object for that string in our map. */
	if(nameToTracker.count(fullname))
	{
		/* If we already have a tracker object, ask it to run the main
		 * loop (and therefore call our handle_tracker() function if
		 * there is new data). */
		nameToTracker[fullname]->mainloop();

		/* If our callback has been called, get the callback object
		 * and get the data out of it. */
		if(nameToCallbackData.count(fullname))
		{
			vrpn_TRACKERCB t = nameToCallbackData[fullname];
			float pos4[4];
			for(int i=0; i<3; i++)
				pos4[i] = t.pos[i];
			pos4[3]=1;

			double orientd[16];
			// Convert quaternion into orientation matrix.
			q_to_ogl_matrix(orientd, t.quat);
			for(int i=0; i<16; i++)
				orient[i] = (float) orientd[i];

			/* IMPORTANT NOTE: The Vicon tracking system is normally
			 * calibrated so that:
			 * X = points to the right (while facing screen)
			 * Y = points into the screen
			 * Z = up
			 *
			 * By default, OpenGL assumes that:
			 * X = points to the right (while facing screen)
			 * Y = up
			 * Z = points OUT of the screen (i.e., -Z points into the screen)
			 *
			 * Below, we convert the Vicon position and orientation
			 * information into the OpenGL convention to make it
			 * easier to add Vicon support to an OpenGL program.
			 *
			 * If you are using this file with a different tracking
			 * system, this conversion may be wrong!
			 */

			float zUpToYUp[16] = { 1,0,0,0,  // column major order!
			                       0,0,-1,0,
			                       0,1,0,0,
			                       0,0,0,1 };
			mat4f_mult_mat4f_new(orient, zUpToYUp, orient);
			mat4f_mult_vec4f_new(pos4, zUpToYUp, pos4);
			vec3f_copy(pos,pos4);
			return 1; // we successfully collected some data
		}
	}
	else
	{
		/* If this is our first time, create a tracker for the object@hostname string, register the callback handler. */
		printf("vrpn-help: Connecting to VRPN server. If this hangs, VRPN server is not running.\n");
		vrpn_Tracker_Remote *tkr = new vrpn_Tracker_Remote(fullname.c_str());
		nameToTracker[fullname] = tkr;
		tkr->register_change_handler((void*) fullname.c_str(), handle_tracker);
	}
	return 0;
#endif
}
} // extern C
<commit_msg>Fix mistake introduced by previous commit<commit_after>/* Copyright (c) 2014 Scott Kuhl. All rights reserved.
 * License: This code is licensed under a 3-clause BSD license. See
 * the file named "LICENSE" for a full copy of the license.
 */

/** @file
 * @author Scott Kuhl
 */
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <string>

#ifndef MISSING_VRPN
#include <vrpn_Tracker.h>
#include <quat.h>
#endif

#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif

#include "kuhl-util.h"
#include "vecmat.h"

#ifndef MISSING_VRPN

/** A mapping of object\@tracker strings to vrpn_Tracker_Remote objects
 * so we can quickly find the appropriate object given an
 * object\@tracker string. */
std::map<std::string, vrpn_Tracker_Remote*> nameToTracker;
/** A mapping of object\@tracker strings to the data that the callback
 * functions store the data into. */
std::map<std::string, vrpn_TRACKERCB> nameToCallbackData;

/** A callback function that will get called whenever the tracked
 * point moves. */
static void VRPN_CALLBACK handle_tracker(void *name, const vrpn_TRACKERCB t)
{
	// Store the data in our map so that someone can use it later.
	std::string s = (char*)name;
	nameToCallbackData[s] = t;
}

#endif

extern "C" {
/** Uses the VRPN library to get the position and orientation of a
 * tracked object.
 *
 * @param object The name of the object being tracked.
 *
 * @param hostname The IP address or hostname of the VRPN server or
 * tracking system computer. If hostname is set to NULL, the IP
 * address of the Vicon tracker in the IVS lab is used.
 *
 * @param pos An array to be filled in with the position information
 * for the tracked object. If we are unable to track the object, a
 * message may be printed and pos will be set to a fixed value.
 *
 * @param orient An array to be filled in with the orientation matrix
 * for the tracked object. The orientation matrix is in row-major
 * order can be used with OpenGL. If the tracking system is moving an
 * object around on the screen, this matrix can be used directly. If
 * the tracking system is moving the OpenGL camera, this matrix may
 * need to be inverted. If we are unable to track the object, a
 * message may be printed and orient will be set to the identity
 * matrix.
 *
 * @return 1 if we returned data from the tracker. 0 if there was
 * problems connecting to the tracker.
 */
int vrpn_get(const char *object, const char *hostname, float pos[3], float orient[16])
{
	/* Set to default values */
	vec3f_set(pos, 10000,10000,10000);
	mat4f_identity(orient);
#ifdef MISSING_VRPN
	printf("You are missing VRPN support.\n");
	return 0;
#else
	/* Construct an object@hostname string. */
	std::string hostnamecpp;
	std::string objectcpp;
	if(hostname == NULL)
	{
		/* Try reading VRPN server information from ~/.vrpn-server

		   This file should contain a single line that says something like:
		   tcp://VRPN.SERVER.IP.ADDR
		 */
		const char *homedir = getenv("HOME");
		char path[1024];
		snprintf(path, 1024, "%s/.vrpn-server", homedir);
		FILE *f = fopen(path, "r");
		if(f == NULL)
		{
			printf("%s: Can't open file %s to get VRPN server information.\n", __func__, path);
			exit(EXIT_FAILURE);
		}
		char vrpnString[1024];
		if(fscanf(f, "%1023s", vrpnString) != 1)
		{
			printf("%s: Can't read %s to get VRPN server information.\n", __func__, path);
			exit(EXIT_FAILURE);
		}
		// printf("%s: Found in %s: %s\n", __func__, path, vrpnString);
		hostnamecpp = vrpnString;
	}

	objectcpp = object;
	std::string fullname = objectcpp + "@" + hostnamecpp;

	/* Check if we have a tracker object for that string in our map. */
	if(nameToTracker.count(fullname))
	{
		/* If we already have a tracker object, ask it to run the main
		 * loop (and therefore call our handle_tracker() function if
		 * there is new data). */
		nameToTracker[fullname]->mainloop();

		/* If our callback has been called, get the callback object
		 * and get the data out of it. */
		if(nameToCallbackData.count(fullname))
		{
			vrpn_TRACKERCB t = nameToCallbackData[fullname];
			float pos4[4];
			for(int i=0; i<3; i++)
				pos4[i] = t.pos[i];
			pos4[3]=1;

			double orientd[16];
			// Convert quaternion into orientation matrix.
			q_to_ogl_matrix(orientd, t.quat);
			for(int i=0; i<16; i++)
				orient[i] = (float) orientd[i];

			/* IMPORTANT NOTE: The Vicon tracking system is normally
			 * calibrated so that:
			 * X = points to the right (while facing screen)
			 * Y = points into the screen
			 * Z = up
			 *
			 * By default, OpenGL assumes that:
			 * X = points to the right (while facing screen)
			 * Y = up
			 * Z = points OUT of the screen (i.e., -Z points into the screen)
			 *
			 * Below, we convert the Vicon position and orientation
			 * information into the OpenGL convention to make it
			 * easier to add Vicon support to an OpenGL program.
			 *
			 * If you are using this file with a different tracking
			 * system, this conversion may be wrong!
			 */

			float zUpToYUp[16] = { 1,0,0,0,  // column major order!
			                       0,0,-1,0,
			                       0,1,0,0,
			                       0,0,0,1 };
			mat4f_mult_mat4f_new(orient, zUpToYUp, orient);
			mat4f_mult_vec4f_new(pos4, zUpToYUp, pos4);
			vec3f_copy(pos,pos4);
			return 1; // we successfully collected some data
		}
	}
	else
	{
		/* If this is our first time, create a tracker for the object@hostname string, register the callback handler. */
		printf("vrpn-help: Connecting to VRPN server. If this hangs, VRPN server is not running.\n");
		vrpn_Tracker_Remote *tkr = new vrpn_Tracker_Remote(fullname.c_str());
		nameToTracker[fullname] = tkr;
		tkr->register_change_handler((void*) fullname.c_str(), handle_tracker);
	}
	return 0;
#endif
}
} // extern C
<|endoftext|>


<commit_before>#ifndef NK_NRAD6_MULTICAST6_HPP_
#define NK_NRAD6_MULTICAST6_HPP_

#include <string>
#include <asio.hpp>
#include "nlsocket.hpp"
extern "C" {
#include "nk/log.h"
}

extern std::unique_ptr<NLSocket> nl_socket;
static void attach_multicast(int fd, const std::string &ifname, asio::ip::address_v6 &mc6addr)
{
    auto ifidx = nl_socket->get_ifindex(ifname);
    struct ifreq ifr;
    memset(&ifr, 0, sizeof (struct ifreq));
    memcpy(ifr.ifr_name, ifname.c_str(), ifname.size());
    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr) < 0)
        suicide("failed to bind socket to device: %s", strerror(errno));
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                   &ifidx, sizeof ifidx) < 0)
        suicide("failed to set multicast interface for socket: %s", strerror(errno));
    int loopback(0);
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
                   &loopback, sizeof loopback) < 0)
        suicide("failed to disable multicast loopback for socket: %s", strerror(errno));
    int hops(255);
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                   &hops, sizeof hops) < 0)
        suicide("failed to disable multicast hops for socket: %s", strerror(errno));
    auto mrb = mc6addr.to_bytes();
    struct ipv6_mreq mr;
    memcpy(&mr.ipv6mr_multiaddr, mrb.data(), sizeof mrb);
    mr.ipv6mr_interface = ifidx;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
                   &mr, sizeof mr) < 0)
        suicide("failed to join router multicast group for socket: %s", strerror(errno));

#if 0
    asio::ip::multicast::join_group mc_routers_group(mc6_allrouters);
    socket_.set_option(mc_routers_group);
#endif

}

#endif

<commit_msg>multicast6: Remove dead code.<commit_after>#ifndef NK_NRAD6_MULTICAST6_HPP_
#define NK_NRAD6_MULTICAST6_HPP_

#include <string>
#include <asio.hpp>
#include "nlsocket.hpp"
extern "C" {
#include "nk/log.h"
}

extern std::unique_ptr<NLSocket> nl_socket;
static void attach_multicast(int fd, const std::string &ifname, asio::ip::address_v6 &mc6addr)
{
    auto ifidx = nl_socket->get_ifindex(ifname);
    struct ifreq ifr;
    memset(&ifr, 0, sizeof (struct ifreq));
    memcpy(ifr.ifr_name, ifname.c_str(), ifname.size());
    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr) < 0)
        suicide("failed to bind socket to device: %s", strerror(errno));
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                   &ifidx, sizeof ifidx) < 0)
        suicide("failed to set multicast interface for socket: %s", strerror(errno));
    int loopback(0);
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
                   &loopback, sizeof loopback) < 0)
        suicide("failed to disable multicast loopback for socket: %s", strerror(errno));
    int hops(255);
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                   &hops, sizeof hops) < 0)
        suicide("failed to disable multicast hops for socket: %s", strerror(errno));
    auto mrb = mc6addr.to_bytes();
    struct ipv6_mreq mr;
    memcpy(&mr.ipv6mr_multiaddr, mrb.data(), sizeof mrb);
    mr.ipv6mr_interface = ifidx;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
                   &mr, sizeof mr) < 0)
        suicide("failed to join router multicast group for socket: %s", strerror(errno));
}

#endif

<|endoftext|>


<commit_before>/**
Copyright (c) 2015, Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Intel Corporation nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.
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 INTEL CORPORATION 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 <cstring>
#include <algorithm>

#include "COO.hpp"
#include "mm_io.h"

using namespace std;

namespace SpMP
{

COO::COO() : rowidx(NULL), colidx(NULL), values(NULL), isSymmetric(false)
{
}

COO::~COO()
{
  dealloc();
}

void COO::dealloc()
{
  FREE(rowidx);
  FREE(colidx);
  FREE(values);
}

void COO::storeMatrixMarket(const char *fileName) const
{
  FILE *fp = fopen(fileName, "w");
  assert(fp);

  MM_typecode matcode;
  mm_initialize_typecode(&matcode);
  mm_set_matrix(&matcode);
  mm_set_sparse(&matcode);
  mm_set_real(&matcode);

  int err = mm_write_mtx_crd(
    (char *)fileName, m, n, nnz, rowidx, colidx, values, matcode);
  if (err) {
    fprintf(
      stderr,
      "Fail to write matrix to %s (error code = %d)\n", fileName, err);
    exit(-1);
  }
}

template<class T>
static void qsort(int *idx, T *w, int left, int right)
{
  if (left >= right) return;

  swap(idx[left], idx[left + (right - left)/2]);
  swap(w[left], w[left + (right - left)/2]);

  int last = left;
  for (int i = left+1; i <= right; i++) {
    if (idx[i] < idx[left]) {
       ++last;
       swap(idx[last], idx[i]);
       swap(w[last], w[i]);
    }
  }

  swap(idx[left], idx[last]);
  swap(w[left], w[last]);

  qsort(idx, w, left, last-1);
  qsort(idx, w, last+1, right);
}

/* converts COO format to CSR format, not in-place,
   if SORT_IN_ROW is defined, each row is sorted in column index.
assume COO is one-based index */

template<class T>
void coo2csr(
  int m, int nnz,
  int *rowptr, int *colidx, T *values,
  const int *cooRowidx, const int *cooColidx, const T *cooValues,
  bool sort)
{
  int i, l;

#pragma omp parallel for
  for (i = 0; i <= m; i++) rowptr[i] = 0;

  /* determine row lengths */
  for (i = 0; i < nnz; i++) rowptr[cooRowidx[i]]++;

  for (i = 0; i < m; i++) rowptr[i+1] += rowptr[i];

  /* go through the structure  once more. Fill in output matrix. */
  for (l = 0; l < nnz; l++) {
    i = rowptr[cooRowidx[l] - 1];
    values[i] = cooValues[l];
    colidx[i] = cooColidx[l] - 1;
    rowptr[cooRowidx[l] - 1]++;
  }

  /* shift back rowptr */
  for (i = m; i>0; i--) rowptr[i] = rowptr[i-1];

  rowptr[0] = 0;

  if (sort) {
#pragma omp parallel for
    for (i=0; i < m; i++){
      qsort(colidx, values, rowptr[i], rowptr[i+1] - 1);
      assert(is_sorted(colidx + rowptr[i], colidx + rowptr[i+1]));
    }
  }
}

void dcoo2csr(
  int m, int nnz,
  int *rowptr, int *colidx, double *values,
  const int *cooRowidx, const int *cooColidx, const double *cooValues,
  bool sort /*=true*/)
{
  coo2csr(m, nnz, rowptr, colidx, values, cooRowidx, cooColidx, cooValues, sort);
}

void dcoo2csr(CSR *Acrs, const COO *Acoo, bool createSeparateDiagData /*= true*/)
{
  Acrs->n=Acoo->n;
  Acrs->m=Acoo->m;

  dcoo2csr(
    Acrs->m, Acoo->nnz,
    Acrs->rowptr, Acrs->colidx, Acrs->values,
    Acoo->rowidx, Acoo->colidx, Acoo->values);

  if (Acrs->diagptr) {
    if (!Acrs->idiag || !Acrs->diag) {
      createSeparateDiagData = false;
    }
#pragma omp parallel for
    for (int i = 0; i < Acrs->m; ++i) {
      for (int j = Acrs->rowptr[i]; j < Acrs->rowptr[i + 1]; ++j) {
        if (Acrs->colidx[j] == i) {
          Acrs->diagptr[i] = j;

          if (createSeparateDiagData) {
            Acrs->idiag[i] = 1/Acrs->values[j];
            Acrs->diag[i] = Acrs->values[j];
          }
        }
      }
    }
  }
}

static bool loadMatrixMarket_(const char *file, COO &coo, bool force_symmetric, bool transpose, int pad)
{
  FILE *fp=fopen(file, "r");
  if (NULL == fp) {
    fprintf(stderr, "Failed to open file %s\n", file);
    exit(-1);
  }

  // read banner
  MM_typecode matcode;
  if (mm_read_banner (fp, &matcode) != 0) {
    fprintf(stderr, "Error: could not process Matrix Market banner.\n");
    fclose(fp);
    return false;
  }

  if (!mm_is_valid (matcode) &&
       (mm_is_array (matcode) || mm_is_dense (matcode)) ) {
    fprintf(stderr, "Error: only support sparse and real matrices.\n");
    fclose(fp);
    return false;
  }
  bool pattern = mm_is_pattern (matcode);

  // read sizes
  int m, n;
  int nnz; // # of non-zeros specified in the file
  if (mm_read_mtx_crd_size(fp, &m, &n, &nnz) !=0) {
    fprintf(stderr, "Error: could not read matrix size.\n");
    fclose(fp);
    return false;
  }
  if (transpose) {
    assert(!force_symmetric);
    swap(m, n);
  }

  int origM = m, origN = n;
  m = (m + pad - 1)/pad*pad;
  n = (n + pad - 1)/pad*pad;

  size_t count;
  if (force_symmetric || mm_is_symmetric (matcode) == 1) {
    coo.isSymmetric = true;
    count = 2L*nnz;
  }
  else {
    count = nnz;
  }

  // allocate memory
  size_t extraCount = min(m, n) - min(origM, origN);
  double *values = MALLOC(double, count + extraCount);
  int *colidx = MALLOC(int, count + extraCount);
  int *rowidx = MALLOC(int, count + extraCount);
  if (!values || !colidx || !rowidx) {
    fprintf(stderr, "Failed to allocate memory\n");
    fclose(fp);
    return false;
  }

  int *colidx_temp, *rowcnt = NULL;
  if (coo.isSymmetric) {
    colidx_temp = MALLOC(int, count);
    rowcnt = MALLOC(int, m + 1);
    if (!colidx_temp || !rowcnt) {
      fprintf(stderr, "Failed to allocate memory\n");
      fclose(fp);
      return false;
    }
    memset(rowcnt, 0, sizeof(int)*(m + 1));
  }

  // read values
  count = 0;
  int lines = 0;
  int x, y;
  double real, imag;
  int base = 1;
  while (mm_read_mtx_crd_entry (fp, &x, &y, &real, &imag, matcode) == 0) {
    if (transpose) swap(x, y);

    if (x > origM || y > origN) {
      fprintf(stderr, "Error: (%d %d) coordinate is out of range.\n", x, y);
      fclose(fp);
      return false;
    }

    rowidx[count] = x;
    colidx[count] = y;
    values[count] = pattern ? 1 : real;
    if (0 == x || 0 == y) base = 0;

    ++count;
    ++lines;
    if (coo.isSymmetric) rowcnt[x]++;
      // this is not a bug. we're intentionally indexing rowcnt[x] instead of rowcnt[x-1]
  }
  // padding for vectorization
  for (int i = min(origM, origN); i < min(m, n); ++i) {
    rowidx[count] = i + 1;
    colidx[count] = i + 1;
    values[count] = 1;
    ++count;
  }
  fclose(fp);

  if (0 == base) {
    for (int i = 0; i < count; ++i) {
      rowidx[i]++;
      colidx[i]++;
    }
    if (coo.isSymmetric) {
      for (int i = m; i > 0; --i) {
        rowcnt[i] = rowcnt[i - 1];
      }
    }
  }

  if (lines != nnz) {
    fprintf(stderr, "Error: nnz (%d) specified in the header doesn't match with # of lines (%d) in file %s\n",
            nnz, lines, file);
    return false;
  }

  if (coo.isSymmetric) {
    // add transposed elements only if it doesn't exist
    size_t real_count = count;
    // preix-sum
    for (int i = 0; i < m; ++i) {
      rowcnt[i + 1] += rowcnt[i];
    }
    for (int i = 0; i < count; ++i) {
      int j = rowcnt[rowidx[i] - 1];
      colidx_temp[j] = colidx[i];
      rowcnt[rowidx[i] - 1]++;
    }
    for (int i = m; i > 0; --i) {
      rowcnt[i] = rowcnt[i - 1];
    }
    rowcnt[0] = 0;

#pragma omp parallel for
    for (int i = 0; i < m; ++i) {
      sort(colidx_temp + rowcnt[i], colidx_temp + rowcnt[i + 1]);
    }

    for (int i = 0; i < count; ++i) {
      int x = rowidx[i], y = colidx[i];
      if (x != y) {
        if (!binary_search(
            colidx_temp + rowcnt[y - 1], colidx_temp + rowcnt[y], x)) {
          rowidx[real_count] = y;
          colidx[real_count] = x;
          values[real_count] = values[i];
          ++real_count;
        }
      }
    }
    count = real_count;

    FREE(rowcnt);
    FREE(colidx_temp);
  }

  coo.m = m;
  coo.n = n;
  coo.nnz = count;
  coo.dealloc();
  coo.values = values;
  coo.colidx = colidx;
  coo.rowidx = rowidx;

  return true;
}

bool loadMatrixMarketTransposed(const char *file, COO &coo, int pad /*= 1*/)
{
  return loadMatrixMarket_(file, coo, false, true /*transpose*/, pad);
}

bool loadMatrixMarket (const char *file, COO &coo, bool force_symmetric /*=false*/, int pad /*=1*/)
{
  return loadMatrixMarket_(file, coo, force_symmetric, false /*no-transpose*/, pad);
}

} // namespace SpMP
<commit_msg>error when trying to read a dense matrix or vector using loadMatrixMarket use loadVectorMatrixMarket for that<commit_after>/**
Copyright (c) 2015, Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Intel Corporation nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.
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 INTEL CORPORATION 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 <cstring>
#include <algorithm>

#include "COO.hpp"
#include "mm_io.h"

using namespace std;

namespace SpMP
{

COO::COO() : rowidx(NULL), colidx(NULL), values(NULL), isSymmetric(false)
{
}

COO::~COO()
{
  dealloc();
}

void COO::dealloc()
{
  FREE(rowidx);
  FREE(colidx);
  FREE(values);
}

void COO::storeMatrixMarket(const char *fileName) const
{
  FILE *fp = fopen(fileName, "w");
  assert(fp);

  MM_typecode matcode;
  mm_initialize_typecode(&matcode);
  mm_set_matrix(&matcode);
  mm_set_sparse(&matcode);
  mm_set_real(&matcode);

  int err = mm_write_mtx_crd(
    (char *)fileName, m, n, nnz, rowidx, colidx, values, matcode);
  if (err) {
    fprintf(
      stderr,
      "Fail to write matrix to %s (error code = %d)\n", fileName, err);
    exit(-1);
  }
}

template<class T>
static void qsort(int *idx, T *w, int left, int right)
{
  if (left >= right) return;

  swap(idx[left], idx[left + (right - left)/2]);
  swap(w[left], w[left + (right - left)/2]);

  int last = left;
  for (int i = left+1; i <= right; i++) {
    if (idx[i] < idx[left]) {
       ++last;
       swap(idx[last], idx[i]);
       swap(w[last], w[i]);
    }
  }

  swap(idx[left], idx[last]);
  swap(w[left], w[last]);

  qsort(idx, w, left, last-1);
  qsort(idx, w, last+1, right);
}

/* converts COO format to CSR format, not in-place,
   if SORT_IN_ROW is defined, each row is sorted in column index.
assume COO is one-based index */

template<class T>
void coo2csr(
  int m, int nnz,
  int *rowptr, int *colidx, T *values,
  const int *cooRowidx, const int *cooColidx, const T *cooValues,
  bool sort)
{
  int i, l;

#pragma omp parallel for
  for (i = 0; i <= m; i++) rowptr[i] = 0;

  /* determine row lengths */
  for (i = 0; i < nnz; i++) rowptr[cooRowidx[i]]++;

  for (i = 0; i < m; i++) rowptr[i+1] += rowptr[i];

  /* go through the structure  once more. Fill in output matrix. */
  for (l = 0; l < nnz; l++) {
    i = rowptr[cooRowidx[l] - 1];
    values[i] = cooValues[l];
    colidx[i] = cooColidx[l] - 1;
    rowptr[cooRowidx[l] - 1]++;
  }

  /* shift back rowptr */
  for (i = m; i>0; i--) rowptr[i] = rowptr[i-1];

  rowptr[0] = 0;

  if (sort) {
#pragma omp parallel for
    for (i=0; i < m; i++){
      qsort(colidx, values, rowptr[i], rowptr[i+1] - 1);
      assert(is_sorted(colidx + rowptr[i], colidx + rowptr[i+1]));
    }
  }
}

void dcoo2csr(
  int m, int nnz,
  int *rowptr, int *colidx, double *values,
  const int *cooRowidx, const int *cooColidx, const double *cooValues,
  bool sort /*=true*/)
{
  coo2csr(m, nnz, rowptr, colidx, values, cooRowidx, cooColidx, cooValues, sort);
}

void dcoo2csr(CSR *Acrs, const COO *Acoo, bool createSeparateDiagData /*= true*/)
{
  Acrs->n=Acoo->n;
  Acrs->m=Acoo->m;

  dcoo2csr(
    Acrs->m, Acoo->nnz,
    Acrs->rowptr, Acrs->colidx, Acrs->values,
    Acoo->rowidx, Acoo->colidx, Acoo->values);

  if (Acrs->diagptr) {
    if (!Acrs->idiag || !Acrs->diag) {
      createSeparateDiagData = false;
    }
#pragma omp parallel for
    for (int i = 0; i < Acrs->m; ++i) {
      for (int j = Acrs->rowptr[i]; j < Acrs->rowptr[i + 1]; ++j) {
        if (Acrs->colidx[j] == i) {
          Acrs->diagptr[i] = j;

          if (createSeparateDiagData) {
            Acrs->idiag[i] = 1/Acrs->values[j];
            Acrs->diag[i] = Acrs->values[j];
          }
        }
      }
    }
  }
}

static bool loadMatrixMarket_(const char *file, COO &coo, bool force_symmetric, bool transpose, int pad)
{
  FILE *fp=fopen(file, "r");
  if (NULL == fp) {
    fprintf(stderr, "Failed to open file %s\n", file);
    exit(-1);
  }

  // read banner
  MM_typecode matcode;
  if (mm_read_banner (fp, &matcode) != 0) {
    fprintf(stderr, "Error: could not process Matrix Market banner.\n");
    fclose(fp);
    return false;
  }

  if (!mm_is_valid (matcode) || mm_is_array (matcode) || mm_is_dense (matcode) ) {
    fprintf(stderr, "Error: only support sparse and real matrices.\n");
    fclose(fp);
    return false;
  }
  bool pattern = mm_is_pattern (matcode);

  // read sizes
  int m, n;
  int nnz; // # of non-zeros specified in the file
  if (mm_read_mtx_crd_size(fp, &m, &n, &nnz) !=0) {
    fprintf(stderr, "Error: could not read matrix size.\n");
    fclose(fp);
    return false;
  }
  if (transpose) {
    assert(!force_symmetric);
    swap(m, n);
  }

  int origM = m, origN = n;
  m = (m + pad - 1)/pad*pad;
  n = (n + pad - 1)/pad*pad;

  size_t count;
  if (force_symmetric || mm_is_symmetric (matcode) == 1) {
    coo.isSymmetric = true;
    count = 2L*nnz;
  }
  else {
    count = nnz;
  }

  // allocate memory
  size_t extraCount = min(m, n) - min(origM, origN);
  double *values = MALLOC(double, count + extraCount);
  int *colidx = MALLOC(int, count + extraCount);
  int *rowidx = MALLOC(int, count + extraCount);
  if (!values || !colidx || !rowidx) {
    fprintf(stderr, "Failed to allocate memory\n");
    fclose(fp);
    return false;
  }

  int *colidx_temp, *rowcnt = NULL;
  if (coo.isSymmetric) {
    colidx_temp = MALLOC(int, count);
    rowcnt = MALLOC(int, m + 1);
    if (!colidx_temp || !rowcnt) {
      fprintf(stderr, "Failed to allocate memory\n");
      fclose(fp);
      return false;
    }
    memset(rowcnt, 0, sizeof(int)*(m + 1));
  }

  // read values
  count = 0;
  int lines = 0;
  int x, y;
  double real, imag;
  int base = 1;
  while (mm_read_mtx_crd_entry (fp, &x, &y, &real, &imag, matcode) == 0) {
    if (transpose) swap(x, y);

    if (x > origM || y > origN) {
      fprintf(stderr, "Error: (%d %d) coordinate is out of range.\n", x, y);
      fclose(fp);
      return false;
    }

    rowidx[count] = x;
    colidx[count] = y;
    values[count] = pattern ? 1 : real;
    if (0 == x || 0 == y) base = 0;

    ++count;
    ++lines;
    if (coo.isSymmetric) rowcnt[x]++;
      // this is not a bug. we're intentionally indexing rowcnt[x] instead of rowcnt[x-1]
  }
  // padding for vectorization
  for (int i = min(origM, origN); i < min(m, n); ++i) {
    rowidx[count] = i + 1;
    colidx[count] = i + 1;
    values[count] = 1;
    ++count;
  }
  fclose(fp);

  if (0 == base) {
    for (int i = 0; i < count; ++i) {
      rowidx[i]++;
      colidx[i]++;
    }
    if (coo.isSymmetric) {
      for (int i = m; i > 0; --i) {
        rowcnt[i] = rowcnt[i - 1];
      }
    }
  }

  if (lines != nnz) {
    fprintf(stderr, "Error: nnz (%d) specified in the header doesn't match with # of lines (%d) in file %s\n",
            nnz, lines, file);
    return false;
  }

  if (coo.isSymmetric) {
    // add transposed elements only if it doesn't exist
    size_t real_count = count;
    // preix-sum
    for (int i = 0; i < m; ++i) {
      rowcnt[i + 1] += rowcnt[i];
    }
    for (int i = 0; i < count; ++i) {
      int j = rowcnt[rowidx[i] - 1];
      colidx_temp[j] = colidx[i];
      rowcnt[rowidx[i] - 1]++;
    }
    for (int i = m; i > 0; --i) {
      rowcnt[i] = rowcnt[i - 1];
    }
    rowcnt[0] = 0;

#pragma omp parallel for
    for (int i = 0; i < m; ++i) {
      sort(colidx_temp + rowcnt[i], colidx_temp + rowcnt[i + 1]);
    }

    for (int i = 0; i < count; ++i) {
      int x = rowidx[i], y = colidx[i];
      if (x != y) {
        if (!binary_search(
            colidx_temp + rowcnt[y - 1], colidx_temp + rowcnt[y], x)) {
          rowidx[real_count] = y;
          colidx[real_count] = x;
          values[real_count] = values[i];
          ++real_count;
        }
      }
    }
    count = real_count;

    FREE(rowcnt);
    FREE(colidx_temp);
  }

  coo.m = m;
  coo.n = n;
  coo.nnz = count;
  coo.dealloc();
  coo.values = values;
  coo.colidx = colidx;
  coo.rowidx = rowidx;

  return true;
}

bool loadMatrixMarketTransposed(const char *file, COO &coo, int pad /*= 1*/)
{
  return loadMatrixMarket_(file, coo, false, true /*transpose*/, pad);
}

bool loadMatrixMarket (const char *file, COO &coo, bool force_symmetric /*=false*/, int pad /*=1*/)
{
  return loadMatrixMarket_(file, coo, force_symmetric, false /*no-transpose*/, pad);
}

} // namespace SpMP
<|endoftext|>


<commit_before>/*******************************************************************************
 * thrill/core/file_io.cpp
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <thrill/common/porting.hpp>
#include <thrill/common/string.hpp>
#include <thrill/common/system_exception.hpp>
#include <thrill/core/file_io.hpp>
#include <thrill/core/simple_glob.hpp>

#include <fcntl.h>
#include <sys/stat.h>

#if !defined(_MSC_VER)

#include <dirent.h>
#include <glob.h>
#include <sys/wait.h>
#include <unistd.h>

#if !defined(O_BINARY)
#define O_BINARY 0
#endif

#else

#include <io.h>
#include <windows.h>

#define S_ISREG(m)       (((m) & _S_IFMT) == _S_IFREG)

#endif

#include <algorithm>
#include <string>
#include <vector>

namespace thrill {
namespace core {

std::string FillFilePattern(const std::string& pathbase,
                            size_t worker, size_t file_part) {

    static const bool debug = false;

    using size_type = std::string::size_type;

    std::string out_path = pathbase;
    {
        // replace dollar
        size_type dollar_end = out_path.rfind('$');
        size_type dollar_begin = out_path.find_last_not_of('$', dollar_end);

        size_type dollar_length =
            dollar_end != std::string::npos && dollar_end > dollar_begin
            ? dollar_end - dollar_begin : 4;

        sLOG << "dollar_length" << dollar_length;
        out_path.replace(dollar_begin + 1, dollar_length,
                         common::str_snprintf<>(dollar_length + 2, "%0*zu",
                                                static_cast<int>(dollar_length),
                                                worker));
    }
    {
        // replace hash signs
        size_type hash_end = out_path.rfind('#');
        size_type hash_begin = out_path.find_last_not_of('#', hash_end);

        size_type hash_length =
            hash_end != std::string::npos && hash_end > hash_begin
            ? hash_end - hash_begin : 10;

        sLOG << "hash_length" << hash_length;
        out_path.replace(hash_begin + 1, hash_length,
                         common::str_snprintf<>(hash_length + 2, "%0*zu",
                                                static_cast<int>(hash_length),
                                                file_part));
    }
    return out_path;
}

std::vector<std::string> GlobFilePattern(const std::string& path) {

    std::vector<std::string> files;

#if defined(_MSC_VER)
    glob_local::CSimpleGlob sglob;
    sglob.Add(path.c_str());
    for (int n = 0; n < sglob.FileCount(); ++n) {
        files.emplace_back(sglob.File(n));
    }
#else
    glob_t glob_result;
    glob(path.c_str(), GLOB_TILDE, nullptr, &glob_result);

    for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
        files.push_back(glob_result.gl_pathv[i]);
    }
    globfree(&glob_result);
#endif

    std::sort(files.begin(), files.end());

    return files;
}

std::vector<FileSizePair> GlobFileSizePrefixSum(const std::string& path) {

    std::vector<FileSizePair> file_size_pairs;
    struct stat filestat;
    size_t directory_size = 0;
    std::vector<std::string> files = GlobFilePattern(path);

    for (const std::string& file : files) {

        if (stat(file.c_str(), &filestat)) {
            throw std::runtime_error(
                      "ERROR: Invalid file " + std::string(file));
        }
        if (!S_ISREG(filestat.st_mode)) continue;

        file_size_pairs.emplace_back(std::move(file), directory_size);
        directory_size += filestat.st_size;
    }
    file_size_pairs.emplace_back("", directory_size);

    return file_size_pairs;
}

/******************************************************************************/

void SysFile::close() {
    if (fd_ >= 0) {
        sLOG << "SysFile::close(): fd" << fd_;
        if (::close(fd_) != 0)
        {
            LOG1 << "SysFile::close()"
                 << " fd_=" << fd_
                 << " errno=" << errno
                 << " error=" << strerror(errno);
        }
        fd_ = -1;
    }
#if !defined(_MSC_VER)
    if (pid_ != 0) {
        sLOG << "SysFile::close(): waitpid for" << pid_;
        int status;
        pid_t p = waitpid(pid_, &status, 0);
        if (p != pid_) {
            throw common::SystemException(
                      "SysFile: waitpid() failed to return child");
        }
        if (WIFEXITED(status)) {
            // child program exited normally
            if (WEXITSTATUS(status) != 0) {
                throw common::ErrnoException(
                          "SysFile: child failed with return code "
                          + std::to_string(WEXITSTATUS(status)));
            }
            else {
                // zero return code. good.
            }
        }
        else if (WIFSIGNALED(status)) {
            throw common::ErrnoException(
                      "SysFile: child killed by signal "
                      + std::to_string(WTERMSIG(status)));
        }
        else {
            throw common::ErrnoException(
                      "SysFile: child failed with an unknown error");
        }
        pid_ = 0;
    }
#endif
}

SysFile SysFile::OpenForRead(const std::string& path) {

    // first open the file and see if it exists at all.

    int fd = open(path.c_str(), O_RDONLY | O_BINARY, 0);
    if (fd < 0) {
        throw common::ErrnoException("Cannot open file " + path);
    }

    // then figure out whether we need to pipe it through a decompressor.

    const char* decompressor;

    if (common::ends_with(path, ".gz")) {
        decompressor = "gzip";
    }
    else if (common::ends_with(path, ".bz2")) {
        decompressor = "bzip2";
    }
    else if (common::ends_with(path, ".xz")) {
        decompressor = "xz";
    }
    else if (common::ends_with(path, ".lzo")) {
        decompressor = "lzop";
    }
    else if (common::ends_with(path, ".lz4")) {
        decompressor = "lz4";
    }
    else {
        // not a compressed file
        common::PortSetCloseOnExec(fd);

        sLOG << "SysFile::OpenForRead(): filefd" << fd;

        return SysFile(fd);
    }

#if defined(_MSC_VER)
    throw common::SystemException(
              "Reading compressed files is not supported on windows, yet. "
              "Please submit a patch.");
#else
    // if decompressor: fork a child program which calls the decompressor and
    // connect file descriptors via a pipe.

    // pipe[0] = read, pipe[1] = write
    int pipefd[2];
    common::make_pipe(pipefd);

    pid_t pid = fork();
    if (pid == 0) {
        // close read end
        ::close(pipefd[0]);

        // replace stdin with file descriptor to file opened above.
        dup2(fd, STDIN_FILENO);
        ::close(fd);
        // replace stdout with pipe going back to Thrill process
        dup2(pipefd[1], STDOUT_FILENO);
        ::close(pipefd[1]);

        execlp(decompressor, decompressor, "-d", nullptr);

        LOG1 << "Pipe execution failed: " << strerror(errno);
        // close write end
        ::close(pipefd[1]);
        exit(-1);
    }
    else if (pid < 0) {
        throw common::ErrnoException("Error creating child process");
    }

    sLOG << "SysFile::OpenForRead(): pipefd" << pipefd[0] << "to pid" << pid;

    // close pipe write end
    ::close(pipefd[1]);

    // close the file descriptor
    ::close(fd);

    return SysFile(pipefd[0], pid);
#endif
}

SysFile SysFile::OpenForWrite(const std::string& path) {

    // first create the file and see if we can write it at all.

    int fd = open(path.c_str(), O_CREAT | O_WRONLY | O_BINARY, 0666);
    if (fd < 0) {
        throw common::ErrnoException("Cannot create file " + path);
    }

    // then figure out whether we need to pipe it through a compressor.

    const char* compressor;

    if (common::ends_with(path, ".gz")) {
        compressor = "gzip";
    }
    else if (common::ends_with(path, ".bz2")) {
        compressor = "bzip2";
    }
    else if (common::ends_with(path, ".xz")) {
        compressor = "xz";
    }
    else if (common::ends_with(path, ".lzo")) {
        compressor = "lzop";
    }
    else if (common::ends_with(path, ".lz4")) {
        compressor = "lz4";
    }
    else {
        // not a compressed file
        common::PortSetCloseOnExec(fd);

        sLOG << "SysFile::OpenForWrite(): filefd" << fd;

        return SysFile(fd);
    }

#if defined(_MSC_VER)
    throw common::SystemException(
              "Reading compressed files is not supported on windows, yet. "
              "Please submit a patch.");
#else
    // if compressor: fork a child program which calls the compressor and
    // connect file descriptors via a pipe.

    // pipe[0] = read, pipe[1] = write
    int pipefd[2];
    common::make_pipe(pipefd);

    pid_t pid = fork();
    if (pid == 0) {
        // close write end
        ::close(pipefd[1]);

        // replace stdin with pipe
        dup2(pipefd[0], STDIN_FILENO);
        ::close(pipefd[0]);
        // replace stdout with file descriptor to file created above.
        dup2(fd, STDOUT_FILENO);
        ::close(fd);

        execlp(compressor, compressor, nullptr);

        LOG1 << "Pipe execution failed: " << strerror(errno);
        // close read end
        ::close(pipefd[0]);
        exit(-1);
    }
    else if (pid < 0) {
        throw common::ErrnoException("Error creating child process");
    }

    sLOG << "SysFile::OpenForWrite(): pipefd" << pipefd[0] << "to pid" << pid;

    // close read end
    ::close(pipefd[0]);

    // close file descriptor (it is used by the fork)
    ::close(fd);

    return SysFile(pipefd[1], pid);
#endif
}

/******************************************************************************/

#if defined(_MSC_VER)

std::string TemporaryDirectory::make_directory(const char* sample) {

    char temp_file_path[MAX_PATH + 1] = { 0 };
    unsigned success = ::GetTempFileName(".", sample, 0, temp_file_path);
    if (!success) {
        throw common::ErrnoException(
                  "Could not allocate temporary directory "
                  + std::string(temp_file_path));
    }

    if (!DeleteFile(temp_file_path)) {
        throw common::ErrnoException(
                  "Could not create temporary directory "
                  + std::string(temp_file_path));
    }

    if (!CreateDirectory(temp_file_path, nullptr)) {
        throw common::ErrnoException(
                  "Could not create temporary directory "
                  + std::string(temp_file_path));
    }

    return temp_file_path;
}

void TemporaryDirectory::wipe_directory(
    const std::string& tmp_dir, bool do_rmdir) {

    WIN32_FIND_DATA ff_data;
    HANDLE h = FindFirstFile((tmp_dir + "\\*").c_str(), &ff_data);

    if (h == INVALID_HANDLE_VALUE) {
        throw common::ErrnoException(
                  "FindFirstFile failed:" + std::to_string(GetLastError()));
    }

    do {
        if (!(ff_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
            std::string path = tmp_dir + "\\" + ff_data.cFileName;

            if (!DeleteFile(path.c_str())) {
                sLOG1 << "Could not unlink temporary file" << path
                      << ":" << strerror(errno);
            }
        }
    } while (FindNextFile(h, &ff_data) != 0);

    DWORD e = GetLastError();
    if (e != ERROR_NO_MORE_FILES) {
        throw common::ErrnoException(
                  "FindFirstFile failed:" + std::to_string(GetLastError()));
    }

    if (!do_rmdir) return;

    if (!RemoveDirectory(tmp_dir.c_str())) {
        throw common::ErrnoException(
                  "Could not remove temporary directory " + tmp_dir);
    }
}

#else

std::string TemporaryDirectory::make_directory(const char* sample) {

    std::string tmp_dir = std::string(sample) + "XXXXXX";
    // evil const_cast, but mkdtemp replaces the XXXXXX with something
    // unique. it also mkdirs.
    char* p = mkdtemp(const_cast<char*>(tmp_dir.c_str()));

    if (p == nullptr) {
        throw common::ErrnoException(
                  "Could create temporary directory " + tmp_dir);
    }

    return tmp_dir;
}

void TemporaryDirectory::wipe_directory(
    const std::string& tmp_dir, bool do_rmdir) {
    DIR* d = opendir(tmp_dir.c_str());
    if (d == nullptr) {
        throw common::ErrnoException(
                  "Could open temporary directory " + tmp_dir);
    }

    struct dirent* de, entry;
    while (readdir_r(d, &entry, &de) == 0 && de != nullptr) {
        // skip ".", "..", and also hidden files (don't create them).
        if (de->d_name[0] == '.') continue;

        std::string path = tmp_dir + "/" + de->d_name;
        int r = unlink(path.c_str());
        if (r != 0)
            sLOG1 << "Could not unlink temporary file" << path
                  << ":" << strerror(errno);
    }

    closedir(d);

    if (!do_rmdir) return;

    if (rmdir(tmp_dir.c_str()) != 0) {
        sLOG1 << "Could not unlink temporary directory" << tmp_dir
              << ":" << strerror(errno);
    }
}

#endif

} // namespace core
} // namespace thrill

/******************************************************************************/
<commit_msg>replace $ with @<commit_after>/*******************************************************************************
 * thrill/core/file_io.cpp
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <thrill/common/porting.hpp>
#include <thrill/common/string.hpp>
#include <thrill/common/system_exception.hpp>
#include <thrill/core/file_io.hpp>
#include <thrill/core/simple_glob.hpp>

#include <fcntl.h>
#include <sys/stat.h>

#if !defined(_MSC_VER)

#include <dirent.h>
#include <glob.h>
#include <sys/wait.h>
#include <unistd.h>

#if !defined(O_BINARY)
#define O_BINARY 0
#endif

#else

#include <io.h>
#include <windows.h>

#define S_ISREG(m)       (((m) & _S_IFMT) == _S_IFREG)

#endif

#include <algorithm>
#include <string>
#include <vector>

namespace thrill {
namespace core {

std::string FillFilePattern(const std::string& pathbase,
                            size_t worker, size_t file_part) {

    static const bool debug = false;

    using size_type = std::string::size_type;

    std::string out_path = pathbase;
    {
        // replace @
        size_type at_end = out_path.rfind('@');
        size_type at_begin = out_path.find_last_not_of('@', at_end);

        size_type at_length =
            at_end != std::string::npos && at_end > at_begin
            ? at_end - at_begin : 4;

        sLOG << "at_length" << at_length;
        out_path.replace(at_begin + 1, at_length,
                         common::str_snprintf<>(at_length + 2, "%0*zu",
                                                static_cast<int>(at_length),
                                                worker));
    }
    {
        // replace hash signs
        size_type hash_end = out_path.rfind('#');
        size_type hash_begin = out_path.find_last_not_of('#', hash_end);

        size_type hash_length =
            hash_end != std::string::npos && hash_end > hash_begin
            ? hash_end - hash_begin : 10;

        sLOG << "hash_length" << hash_length;
        out_path.replace(hash_begin + 1, hash_length,
                         common::str_snprintf<>(hash_length + 2, "%0*zu",
                                                static_cast<int>(hash_length),
                                                file_part));
    }
    return out_path;
}

std::vector<std::string> GlobFilePattern(const std::string& path) {

    std::vector<std::string> files;

#if defined(_MSC_VER)
    glob_local::CSimpleGlob sglob;
    sglob.Add(path.c_str());
    for (int n = 0; n < sglob.FileCount(); ++n) {
        files.emplace_back(sglob.File(n));
    }
#else
    glob_t glob_result;
    glob(path.c_str(), GLOB_TILDE, nullptr, &glob_result);

    for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
        files.push_back(glob_result.gl_pathv[i]);
    }
    globfree(&glob_result);
#endif

    std::sort(files.begin(), files.end());

    return files;
}

std::vector<FileSizePair> GlobFileSizePrefixSum(const std::string& path) {

    std::vector<FileSizePair> file_size_pairs;
    struct stat filestat;
    size_t directory_size = 0;
    std::vector<std::string> files = GlobFilePattern(path);

    for (const std::string& file : files) {

        if (stat(file.c_str(), &filestat)) {
            throw std::runtime_error(
                      "ERROR: Invalid file " + std::string(file));
        }
        if (!S_ISREG(filestat.st_mode)) continue;

        file_size_pairs.emplace_back(std::move(file), directory_size);
        directory_size += filestat.st_size;
    }
    file_size_pairs.emplace_back("", directory_size);

    return file_size_pairs;
}

/******************************************************************************/

void SysFile::close() {
    if (fd_ >= 0) {
        sLOG << "SysFile::close(): fd" << fd_;
        if (::close(fd_) != 0)
        {
            LOG1 << "SysFile::close()"
                 << " fd_=" << fd_
                 << " errno=" << errno
                 << " error=" << strerror(errno);
        }
        fd_ = -1;
    }
#if !defined(_MSC_VER)
    if (pid_ != 0) {
        sLOG << "SysFile::close(): waitpid for" << pid_;
        int status;
        pid_t p = waitpid(pid_, &status, 0);
        if (p != pid_) {
            throw common::SystemException(
                      "SysFile: waitpid() failed to return child");
        }
        if (WIFEXITED(status)) {
            // child program exited normally
            if (WEXITSTATUS(status) != 0) {
                throw common::ErrnoException(
                          "SysFile: child failed with return code "
                          + std::to_string(WEXITSTATUS(status)));
            }
            else {
                // zero return code. good.
            }
        }
        else if (WIFSIGNALED(status)) {
            throw common::ErrnoException(
                      "SysFile: child killed by signal "
                      + std::to_string(WTERMSIG(status)));
        }
        else {
            throw common::ErrnoException(
                      "SysFile: child failed with an unknown error");
        }
        pid_ = 0;
    }
#endif
}

SysFile SysFile::OpenForRead(const std::string& path) {

    // first open the file and see if it exists at all.

    int fd = open(path.c_str(), O_RDONLY | O_BINARY, 0);
    if (fd < 0) {
        throw common::ErrnoException("Cannot open file " + path);
    }

    // then figure out whether we need to pipe it through a decompressor.

    const char* decompressor;

    if (common::ends_with(path, ".gz")) {
        decompressor = "gzip";
    }
    else if (common::ends_with(path, ".bz2")) {
        decompressor = "bzip2";
    }
    else if (common::ends_with(path, ".xz")) {
        decompressor = "xz";
    }
    else if (common::ends_with(path, ".lzo")) {
        decompressor = "lzop";
    }
    else if (common::ends_with(path, ".lz4")) {
        decompressor = "lz4";
    }
    else {
        // not a compressed file
        common::PortSetCloseOnExec(fd);

        sLOG << "SysFile::OpenForRead(): filefd" << fd;

        return SysFile(fd);
    }

#if defined(_MSC_VER)
    throw common::SystemException(
              "Reading compressed files is not supported on windows, yet. "
              "Please submit a patch.");
#else
    // if decompressor: fork a child program which calls the decompressor and
    // connect file descriptors via a pipe.

    // pipe[0] = read, pipe[1] = write
    int pipefd[2];
    common::make_pipe(pipefd);

    pid_t pid = fork();
    if (pid == 0) {
        // close read end
        ::close(pipefd[0]);

        // replace stdin with file descriptor to file opened above.
        dup2(fd, STDIN_FILENO);
        ::close(fd);
        // replace stdout with pipe going back to Thrill process
        dup2(pipefd[1], STDOUT_FILENO);
        ::close(pipefd[1]);

        execlp(decompressor, decompressor, "-d", nullptr);

        LOG1 << "Pipe execution failed: " << strerror(errno);
        // close write end
        ::close(pipefd[1]);
        exit(-1);
    }
    else if (pid < 0) {
        throw common::ErrnoException("Error creating child process");
    }

    sLOG << "SysFile::OpenForRead(): pipefd" << pipefd[0] << "to pid" << pid;

    // close pipe write end
    ::close(pipefd[1]);

    // close the file descriptor
    ::close(fd);

    return SysFile(pipefd[0], pid);
#endif
}

SysFile SysFile::OpenForWrite(const std::string& path) {

    // first create the file and see if we can write it at all.

    int fd = open(path.c_str(), O_CREAT | O_WRONLY | O_BINARY, 0666);
    if (fd < 0) {
        throw common::ErrnoException("Cannot create file " + path);
    }

    // then figure out whether we need to pipe it through a compressor.

    const char* compressor;

    if (common::ends_with(path, ".gz")) {
        compressor = "gzip";
    }
    else if (common::ends_with(path, ".bz2")) {
        compressor = "bzip2";
    }
    else if (common::ends_with(path, ".xz")) {
        compressor = "xz";
    }
    else if (common::ends_with(path, ".lzo")) {
        compressor = "lzop";
    }
    else if (common::ends_with(path, ".lz4")) {
        compressor = "lz4";
    }
    else {
        // not a compressed file
        common::PortSetCloseOnExec(fd);

        sLOG << "SysFile::OpenForWrite(): filefd" << fd;

        return SysFile(fd);
    }

#if defined(_MSC_VER)
    throw common::SystemException(
              "Reading compressed files is not supported on windows, yet. "
              "Please submit a patch.");
#else
    // if compressor: fork a child program which calls the compressor and
    // connect file descriptors via a pipe.

    // pipe[0] = read, pipe[1] = write
    int pipefd[2];
    common::make_pipe(pipefd);

    pid_t pid = fork();
    if (pid == 0) {
        // close write end
        ::close(pipefd[1]);

        // replace stdin with pipe
        dup2(pipefd[0], STDIN_FILENO);
        ::close(pipefd[0]);
        // replace stdout with file descriptor to file created above.
        dup2(fd, STDOUT_FILENO);
        ::close(fd);

        execlp(compressor, compressor, nullptr);

        LOG1 << "Pipe execution failed: " << strerror(errno);
        // close read end
        ::close(pipefd[0]);
        exit(-1);
    }
    else if (pid < 0) {
        throw common::ErrnoException("Error creating child process");
    }

    sLOG << "SysFile::OpenForWrite(): pipefd" << pipefd[0] << "to pid" << pid;

    // close read end
    ::close(pipefd[0]);

    // close file descriptor (it is used by the fork)
    ::close(fd);

    return SysFile(pipefd[1], pid);
#endif
}

/******************************************************************************/

#if defined(_MSC_VER)

std::string TemporaryDirectory::make_directory(const char* sample) {

    char temp_file_path[MAX_PATH + 1] = { 0 };
    unsigned success = ::GetTempFileName(".", sample, 0, temp_file_path);
    if (!success) {
        throw common::ErrnoException(
                  "Could not allocate temporary directory "
                  + std::string(temp_file_path));
    }

    if (!DeleteFile(temp_file_path)) {
        throw common::ErrnoException(
                  "Could not create temporary directory "
                  + std::string(temp_file_path));
    }

    if (!CreateDirectory(temp_file_path, nullptr)) {
        throw common::ErrnoException(
                  "Could not create temporary directory "
                  + std::string(temp_file_path));
    }

    return temp_file_path;
}

void TemporaryDirectory::wipe_directory(
    const std::string& tmp_dir, bool do_rmdir) {

    WIN32_FIND_DATA ff_data;
    HANDLE h = FindFirstFile((tmp_dir + "\\*").c_str(), &ff_data);

    if (h == INVALID_HANDLE_VALUE) {
        throw common::ErrnoException(
                  "FindFirstFile failed:" + std::to_string(GetLastError()));
    }

    do {
        if (!(ff_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
            std::string path = tmp_dir + "\\" + ff_data.cFileName;

            if (!DeleteFile(path.c_str())) {
                sLOG1 << "Could not unlink temporary file" << path
                      << ":" << strerror(errno);
            }
        }
    } while (FindNextFile(h, &ff_data) != 0);

    DWORD e = GetLastError();
    if (e != ERROR_NO_MORE_FILES) {
        throw common::ErrnoException(
                  "FindFirstFile failed:" + std::to_string(GetLastError()));
    }

    if (!do_rmdir) return;

    if (!RemoveDirectory(tmp_dir.c_str())) {
        throw common::ErrnoException(
                  "Could not remove temporary directory " + tmp_dir);
    }
}

#else

std::string TemporaryDirectory::make_directory(const char* sample) {

    std::string tmp_dir = std::string(sample) + "XXXXXX";
    // evil const_cast, but mkdtemp replaces the XXXXXX with something
    // unique. it also mkdirs.
    char* p = mkdtemp(const_cast<char*>(tmp_dir.c_str()));

    if (p == nullptr) {
        throw common::ErrnoException(
                  "Could create temporary directory " + tmp_dir);
    }

    return tmp_dir;
}

void TemporaryDirectory::wipe_directory(
    const std::string& tmp_dir, bool do_rmdir) {
    DIR* d = opendir(tmp_dir.c_str());
    if (d == nullptr) {
        throw common::ErrnoException(
                  "Could open temporary directory " + tmp_dir);
    }

    struct dirent* de, entry;
    while (readdir_r(d, &entry, &de) == 0 && de != nullptr) {
        // skip ".", "..", and also hidden files (don't create them).
        if (de->d_name[0] == '.') continue;

        std::string path = tmp_dir + "/" + de->d_name;
        int r = unlink(path.c_str());
        if (r != 0)
            sLOG1 << "Could not unlink temporary file" << path
                  << ":" << strerror(errno);
    }

    closedir(d);

    if (!do_rmdir) return;

    if (rmdir(tmp_dir.c_str()) != 0) {
        sLOG1 << "Could not unlink temporary directory" << tmp_dir
              << ":" << strerror(errno);
    }
}

#endif

} // namespace core
} // namespace thrill

/******************************************************************************/
<|endoftext|>


<commit_before>/*
 * \copyright Copyright 2014 Xiang Zhang. All Rights Reserved.
 * \license @{
 *
 * 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.
 *
 * @}
 */

#ifndef THUNDER_STORAGE_INL_HPP
#define THUNDER_STORAGE_INL_HPP

#include "thunder/storage.hpp"

#include <initializer_list>
#include <memory>
#include <stdexcept>

namespace thunder {

template <typename T, typename A >
Storage<T, A>::Storage(const A &alloc = A())
    : alloc_(alloc), size_(0), data_(nullptr) {}

template <typename T, typename A >
Storage<T, A>::Storage(size_type count, const A &alloc = A())
    : alloc_(alloc), size_(count),
      data_(size_ == 0 ? nullptr : alloc_.allocate(size_)){}

template <typename T, typename A >
Storage<T, A>::Storage(size_type count, const T& value, const A &alloc = A())
    : alloc_(alloc), size_(count),
      data_(size_ == 0 ? nullptr : alloc_.allocate(size_)){
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = value;
  }
}

template <typename T, typename A >
Storage<T, A>::Storage(const Storage &other)
  : alloc_(other.alloc_), size_(other.size_),
    data_(size_ == 0 ? nullptr : alloc_.allocate(size_)) {
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = other.data_[i];
  }
}

template <typename T, typename A >
Storage<T, A>::Storage(Storage &&other)
    : alloc_(::std::move(other.alloc_)), size_(::std::move(other.size_)),
      data_(other.data_) {
  other.data_ = nullptr;
}

template <typename T, typename A >
Storage<T, A>::~Storage() {
  if (data_ != nullptr) {
    alloc_.deallocate(data_, size_);
  }
}

template <typename T, typename A >
Storage<T, A>& Storage<T,A>::operator=(const Storage &other) {
  Resize(other.size_);
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = other.data_[i];
  }
  return *this;
}

template <typename T, typename A >
Storage<T, A>& Storage<T,A>::operator=(Storage && other) {
  if (data_ != nullptr) {
    alloc_.deallocate(data_, size_);
  }
  size_ = ::std::move(other.size_);
  data_ = other.data_;
  other.data_ = nullptr;
  return *this;
}

template <typename T, typename A >
Storage<T,A>::reference Storage<T,A>::operator[](size_type pos) {
  return data_[pos];
}

template <typename T, typename A >
Storage<T,A>::const_reference Storage<T,A>::operator[](size_type pos) const {
  return data_[pos];
}

template <typename T, typename A >
Storage<T,A>::pointer Storage<T,A>::Data() {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::const_pointer Storage<T,A>::Data() const {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::iterator Storage<T,A>::begin() {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::const_iterator Storage<T,A>::begin() const {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::iterator Storage<T,A>::end() {
  return data_ + size_;
}

template <typename T, typename A >
Storage<T,A>::const_iterator Storage<T,A>::end() const {
  return data_ + size_;
}

template<typename T, typename A >
template<typename Other_T, typename Other_A>
void Storage<T,A>::Copy(const Storage<Other_T, Other_A> &other) {
  Resize(static_cast<size_type>(other.Size()));
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = static_cast<T> (other[static_cast<other::size_type>(i)]);
  }
}

template <typename T, typename A >
void Storage<T,A>::Resize(size_type count) {
  pointer data = nullptr;
  if (count > 0) {
    data = alloc_.allocate(count, data_);
  }
  if (data_ != nullptr) {
    alloc_.deallocate(data_, size_);
  }
  size_ = count;
  data_ = data;
}

template <typename T, typename A >
void Storage<T,A>::Resize(size_type count, const T &value) {
  Resize(count);
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = value;
  }
}

// Check the size of the storage
template <typename T, typename A >
Storage<T,A>::size_type Storage<T,A>::Size() const {
  return size_;
}

}  // namespace thunder

#endif  // THUNDER_STORAGE_INL_HPP
<commit_msg>Remove unnecessary comments<commit_after>/*
 * \copyright Copyright 2014 Xiang Zhang. All Rights Reserved.
 * \license @{
 *
 * 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.
 *
 * @}
 */

#ifndef THUNDER_STORAGE_INL_HPP
#define THUNDER_STORAGE_INL_HPP

#include "thunder/storage.hpp"

#include <initializer_list>
#include <memory>
#include <stdexcept>

namespace thunder {

template <typename T, typename A >
Storage<T, A>::Storage(const A &alloc = A())
    : alloc_(alloc), size_(0), data_(nullptr) {}

template <typename T, typename A >
Storage<T, A>::Storage(size_type count, const A &alloc = A())
    : alloc_(alloc), size_(count),
      data_(size_ == 0 ? nullptr : alloc_.allocate(size_)){}

template <typename T, typename A >
Storage<T, A>::Storage(size_type count, const T& value, const A &alloc = A())
    : alloc_(alloc), size_(count),
      data_(size_ == 0 ? nullptr : alloc_.allocate(size_)){
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = value;
  }
}

template <typename T, typename A >
Storage<T, A>::Storage(const Storage &other)
  : alloc_(other.alloc_), size_(other.size_),
    data_(size_ == 0 ? nullptr : alloc_.allocate(size_)) {
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = other.data_[i];
  }
}

template <typename T, typename A >
Storage<T, A>::Storage(Storage &&other)
    : alloc_(::std::move(other.alloc_)), size_(::std::move(other.size_)),
      data_(other.data_) {
  other.data_ = nullptr;
}

template <typename T, typename A >
Storage<T, A>::~Storage() {
  if (data_ != nullptr) {
    alloc_.deallocate(data_, size_);
  }
}

template <typename T, typename A >
Storage<T, A>& Storage<T,A>::operator=(const Storage &other) {
  Resize(other.size_);
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = other.data_[i];
  }
  return *this;
}

template <typename T, typename A >
Storage<T, A>& Storage<T,A>::operator=(Storage && other) {
  if (data_ != nullptr) {
    alloc_.deallocate(data_, size_);
  }
  size_ = ::std::move(other.size_);
  data_ = other.data_;
  other.data_ = nullptr;
  return *this;
}

template <typename T, typename A >
Storage<T,A>::reference Storage<T,A>::operator[](size_type pos) {
  return data_[pos];
}

template <typename T, typename A >
Storage<T,A>::const_reference Storage<T,A>::operator[](size_type pos) const {
  return data_[pos];
}

template <typename T, typename A >
Storage<T,A>::pointer Storage<T,A>::Data() {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::const_pointer Storage<T,A>::Data() const {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::iterator Storage<T,A>::begin() {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::const_iterator Storage<T,A>::begin() const {
  return data_;
}

template <typename T, typename A >
Storage<T,A>::iterator Storage<T,A>::end() {
  return data_ + size_;
}

template <typename T, typename A >
Storage<T,A>::const_iterator Storage<T,A>::end() const {
  return data_ + size_;
}

template<typename T, typename A >
template<typename Other_T, typename Other_A>
void Storage<T,A>::Copy(const Storage<Other_T, Other_A> &other) {
  Resize(static_cast<size_type>(other.Size()));
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = static_cast<T> (other[static_cast<other::size_type>(i)]);
  }
}

template <typename T, typename A >
void Storage<T,A>::Resize(size_type count) {
  pointer data = nullptr;
  if (count > 0) {
    data = alloc_.allocate(count, data_);
  }
  if (data_ != nullptr) {
    alloc_.deallocate(data_, size_);
  }
  size_ = count;
  data_ = data;
}

template <typename T, typename A >
void Storage<T,A>::Resize(size_type count, const T &value) {
  Resize(count);
  for(size_type i = 0; i < size_; ++i) {
    data_[i] = value;
  }
}

template <typename T, typename A >
Storage<T,A>::size_type Storage<T,A>::Size() const {
  return size_;
}

}  // namespace thunder

#endif  // THUNDER_STORAGE_INL_HPP
<|endoftext|>