/**
 *
 * @file trace/portable_archive_exception.hpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Mathieu Faverge
 * @author Johnny Jazeix
 *
 * @date 2024-07-17
 */
#pragma once

#include <boost/lexical_cast.hpp>
#include <boost/archive/basic_archive.hpp>
#include <boost/archive/archive_exception.hpp>

namespace eos {

// this value is written to the top of the stream
const signed char magic_byte = 'e' | 'o' | 's';

// flag for fp serialization
const unsigned no_infnan = 64;

// integral type for the archive version
#if BOOST_VERSION < 104400
typedef boost::archive::version_type archive_version_type;
#else
typedef boost::archive::library_version_type archive_version_type;
#endif

// version of the linked boost archive library
const archive_version_type archive_version(
#if BOOST_VERSION < 103700
    boost::archive::ARCHIVE_VERSION()
#else
    boost::archive::BOOST_ARCHIVE_VERSION()
#endif
);

/**
 * \brief Exception being thrown when serialization cannot proceed.
 *
 * There are several situations in which the portable archives may fail and
 * hence throw an exception:
 * -# deserialization of an integer value that exceeds the range of the type
 * -# (de)serialization of inf/nan through an archive with no_infnan flag set
 * -# deserialization of a denormalized value without the floating point type
 *    supporting denormalized numbers
 *
 * Note that this exception will also be thrown if you mixed up your stream
 * position and accidentially interpret some value for size data (in this case
 * the reported size will be totally amiss most of the time).
 */
class portable_archive_exception : public boost::archive::archive_exception
{
    std::string msg;

public:
    //! type size is not large enough for deserialized number
    portable_archive_exception(signed char invalid_size) :
        boost::archive::archive_exception(other_exception), msg("requested integer size exceeds type size: ") {
        msg += boost::lexical_cast<std::string, int>(invalid_size);
    }

    //! negative number in unsigned type
    portable_archive_exception() :
        boost::archive::archive_exception(other_exception), msg("cannot read a negative number into an unsigned type") {
    }

    //! serialization of inf, nan and denormals
    template <typename T>
    portable_archive_exception(const T &abnormal) :
        boost::archive::archive_exception(other_exception), msg("serialization of illegal floating point value: ") {
        msg += boost::lexical_cast<std::string>(abnormal);
    }

    //! override the base class function with our message
    const char *what() const throw() { return msg.c_str(); }
    ~portable_archive_exception() throw() { }
};

} // namespace eos
