Program Listing for File archive.h

Return to documentation for file (include/coal/serialization/archive.h)

//
// Copyright (c) 2017-2024 CNRS INRIA
// This file was borrowed from the Pinocchio library:
// https://github.com/stack-of-tasks/pinocchio
//

#ifndef COAL_SERIALIZATION_ARCHIVE_H
#define COAL_SERIALIZATION_ARCHIVE_H

#include "coal/fwd.hh"

#include <boost/serialization/nvp.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

#include <fstream>
#include <string>
#include <sstream>
#include <stdexcept>

#if BOOST_VERSION / 100 % 1000 == 78 && __APPLE__
// See https://github.com/qcscine/utilities/issues/5#issuecomment-1246897049 for
// further details

#ifndef BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC
#define DEFINE_BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC
#define BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC
#endif

#include <boost/asio/streambuf.hpp>

#ifdef DEFINE_BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC
#undef BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC
#endif

#else
#include <boost/asio/streambuf.hpp>
#endif

#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>

// Handle NAN inside TXT or XML archives
#include <boost/math/special_functions/nonfinite_num_facets.hpp>

namespace coal {
namespace serialization {

template <typename T>
inline void loadFromText(T& object, const std::string& filename) {
  std::ifstream ifs(filename.c_str());
  if (ifs) {
    std::locale const new_loc(ifs.getloc(),
                              new boost::math::nonfinite_num_get<char>);
    ifs.imbue(new_loc);
    boost::archive::text_iarchive ia(ifs, boost::archive::no_codecvt);
    ia >> object;
  } else {
    const std::string exception_message(filename +
                                        " does not seem to be a valid file.");
    throw std::invalid_argument(exception_message);
  }
}

template <typename T>
inline void saveToText(const T& object, const std::string& filename) {
  std::ofstream ofs(filename.c_str());
  if (ofs) {
    boost::archive::text_oarchive oa(ofs);
    oa & object;
  } else {
    const std::string exception_message(filename +
                                        " does not seem to be a valid file.");
    throw std::invalid_argument(exception_message);
  }
}

template <typename T>
inline void loadFromStringStream(T& object, std::istringstream& is) {
  std::locale const new_loc(is.getloc(),
                            new boost::math::nonfinite_num_get<char>);
  is.imbue(new_loc);
  boost::archive::text_iarchive ia(is, boost::archive::no_codecvt);
  ia >> object;
}

template <typename T>
inline void saveToStringStream(const T& object, std::stringstream& ss) {
  boost::archive::text_oarchive oa(ss);
  oa & object;
}

template <typename T>
inline void loadFromString(T& object, const std::string& str) {
  std::istringstream is(str);
  loadFromStringStream(object, is);
}

template <typename T>
inline std::string saveToString(const T& object) {
  std::stringstream ss;
  saveToStringStream(object, ss);
  return ss.str();
}

template <typename T>
inline void loadFromXML(T& object, const std::string& filename,
                        const std::string& tag_name) {
  if (filename.empty()) {
    COAL_THROW_PRETTY("Tag name should not be empty.", std::invalid_argument);
  }

  std::ifstream ifs(filename.c_str());
  if (ifs) {
    std::locale const new_loc(ifs.getloc(),
                              new boost::math::nonfinite_num_get<char>);
    ifs.imbue(new_loc);
    boost::archive::xml_iarchive ia(ifs, boost::archive::no_codecvt);
    ia >> boost::serialization::make_nvp(tag_name.c_str(), object);
  } else {
    const std::string exception_message(filename +
                                        " does not seem to be a valid file.");
    throw std::invalid_argument(exception_message);
  }
}

template <typename T>
inline void saveToXML(const T& object, const std::string& filename,
                      const std::string& tag_name) {
  if (filename.empty()) {
    COAL_THROW_PRETTY("Tag name should not be empty.", std::invalid_argument);
  }

  std::ofstream ofs(filename.c_str());
  if (ofs) {
    boost::archive::xml_oarchive oa(ofs);
    oa& boost::serialization::make_nvp(tag_name.c_str(), object);
  } else {
    const std::string exception_message(filename +
                                        " does not seem to be a valid file.");
    throw std::invalid_argument(exception_message);
  }
}

template <typename T>
inline void loadFromBinary(T& object, const std::string& filename) {
  std::ifstream ifs(filename.c_str(), std::ios::binary);
  if (ifs) {
    boost::archive::binary_iarchive ia(ifs);
    ia >> object;
  } else {
    const std::string exception_message(filename +
                                        " does not seem to be a valid file.");
    throw std::invalid_argument(exception_message);
  }
}

template <typename T>
void saveToBinary(const T& object, const std::string& filename) {
  std::ofstream ofs(filename.c_str(), std::ios::binary);
  if (ofs) {
    boost::archive::binary_oarchive oa(ofs);
    oa & object;
  } else {
    const std::string exception_message(filename +
                                        " does not seem to be a valid file.");
    throw std::invalid_argument(exception_message);
  }
}

template <typename T>
inline void loadFromBuffer(T& object, boost::asio::streambuf& buffer) {
  boost::archive::binary_iarchive ia(buffer);
  ia >> object;
}

template <typename T>
void saveToBuffer(const T& object, boost::asio::streambuf& buffer) {
  boost::archive::binary_oarchive oa(buffer);
  oa & object;
}

}  // namespace serialization
}  // namespace coal

#endif  // ifndef COAL_SERIALIZATION_ARCHIVE_H