<commit_before>/// Part of: https://github.com/mateidavid/hpptools

/// @author    Matei David, Ontario Institute for Cancer Research
/// @version   1.0
/// @date      2013-2017
/// @copyright MIT Public License
///
/// Logger mechanism.
///
/// Properties:
/// - thread-safe, non-garbled output (uses c++11's thread_local)
/// - customizable ostream sink. by default, uses std::clog
///
/// Exports:
/// - "LOG" macro (takes 1, 2, or 3 arguments, see below)
/// - "logger" namespace
/// - "logger::level" enum
/// - "logger::Logger" class
///
/// To use:
/// - In source code, use:
///
///     LOG(info) << "hello" << endl;
///     // or
///     LOG("main", info) << "hello" << endl;
///     // or
///     LOG("main", info, sink_os) << "hello" << endl;
///
///   Here, "main" is the facility (a string) and info is the message level.
///   Note that "logger" is a macro which knows how to look up the name info
///   inside logger namespace. The macro introduces C++ code equivalent to:
///
///     if (...message should be ignored...) then; else sink_os
///
///   NOTE: As with assert(), the code in the output stream following the
///   LOG() macro will ***not be executed*** if the log level of the
///   facility is higher than the level of the message.
///
/// - To set the default log level (for unspecified facilities):
///
///     logger::Logger::set_default_level(logger::Logger::level_from_string(s));
///
/// - To set the log level for the "main" facility:
///
///     logger::Logger::set_facility_level("main", logger::Logger::level_from_string(s));
///
/// - To parse a log facility level setting in the form "[<facility>:]<level>":
///
///     logger::Logger::set_level_from_option("alt:debug1", &cerr);
///
/// - By using these functions, one can set log levels using command-line
///   parameters and achieve dynamic log level settings without recompiling.

#ifndef __LOGGER_HPP
#define __LOGGER_HPP

#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <iostream>
#include <mutex>

namespace logger
{

// log levels
enum level
{
    error = 0,
    warning,
    info,
    debug,
    debug1,
    debug2
};

class Logger
    : public std::ostringstream
{
public:
    // Constructor: initialize buffer.
    Logger(const std::string& facility, level msg_level,
           const std::string& file_name, unsigned line_num, const std::string& func_name,
           std::ostream& os = std::clog)
        : _os_p(&os), _policy(0)
    {
        *this << "= " << facility << "." << int(msg_level)
              << " " << file_name << ":" << line_num
              << " " << func_name << " ";
    }
    Logger(int policy, const std::string& file_name, unsigned line_num, const std::string& func_name,
           std::ostream& os = std::cerr)
        : _os_p(&os), _policy(policy)
    {
        *this << "= main." << int(error)
              << " " << file_name << ":" << line_num
              << " " << func_name << " ";
    }
    // Destructor: dump buffer to output.
    ~Logger()
    {
        _os_p->write(this->str().c_str(), this->str().size());
        if (_policy < 0) std::abort();
        if (_policy > 0) std::exit(_policy);
    }
    // Produce l-value for output chaining.
    std::ostream& l_value() { return *this; }

    // static methods for setting and getting facility log levels.
    static level get_default_level()
    {
        return default_level();
    }
    static void set_default_level(level l)
    {
        static std::mutex m;
        std::lock_guard< std::mutex > lg(m);
        default_level() = l;
    }
    static void set_default_level(int l)
    {
        set_default_level(get_level(l));
    }
    static void set_default_level(const std::string& s)
    {
        set_default_level(get_level(s));
    }
    static level get_facility_level(const std::string& facility)
    {
        return (facility_level_map().count(facility) > 0?
                facility_level_map().at(facility) : get_default_level());
    }
    static void set_facility_level(const std::string& facility, level l)
    {
        static std::mutex m;
        std::lock_guard< std::mutex > lg(m);
        facility_level_map()[facility] = l;
    }
    static void set_facility_level(const std::string& facility, int l)
    {
        set_facility_level(facility, get_level(l));
    }
    static void set_facility_level(const std::string& facility, const std::string& s)
    {
        set_facility_level(facility, get_level(s));
    }
    // static methods for setting log levels from command-line options
    static void set_level_from_option(const std::string& l, std::ostream* os_p = nullptr)
    {
        size_t i = l.find(':');
        if (i == std::string::npos)
        {
            set_default_level(l);
            if (os_p)
            {
                (*os_p) << "set default log level to: "
                        << static_cast< int >(Logger::get_default_level()) << std::endl;
            }
        }
        else
        {
            set_facility_level(l.substr(0, i), l.substr(i + 1));
            if (os_p)
            {
                (*os_p) << "set log level of '" << l.substr(0, i) << "' to: "
                        << static_cast< int >(Logger::get_facility_level(l.substr(0, i))) << std::endl;
            }
        }
    }
    static void set_levels_from_options(const std::vector< std::string >& v, std::ostream* os_p = nullptr)
    {
        for (const auto& l : v)
        {
            set_level_from_option(l, os_p);
        }
    }
    // public static utility functions (used by LOG macro)
    static level get_level(level l) { return l; }
    static level get_level(int i) { return static_cast< level >(i); }
    static level get_level(const std::string& s) { return level_from_string(s); }
    // public static member (used by LOG macro)
    static level& thread_local_last_level()
    {
        static thread_local level _last_level = error;
        return _last_level;
    }
private:
    // sink for this Logger object
    std::ostream* _os_p;
    int _policy;

    // private static data members
    static level& default_level()
    {
        static level _default_level = error;
        return _default_level;
    }
    static std::map< std::string, level >& facility_level_map()
    {
        static std::map< std::string, level > _facility_level_map;
        return _facility_level_map;
    }
    // private static utility functions
    static level level_from_string(const std::string& s)
    {
        std::istringstream iss(s + "\n");
        int tmp_int = -1;
        iss >> tmp_int;
        if (iss.good())
        {
            return level(tmp_int);
        }
        else
        {
            if (s == "error") return logger::error;
            else if (s == "warning") return logger::warning;
            else if (s == "info") return logger::info;
            else if (s == "debug") return logger::debug;
            else if (s == "debug1") return logger::debug1;
            else if (s == "debug2") return logger::debug2;
            else
            {
                std::ostringstream oss;
                oss << "could not parse log level: " << s;
                throw std::invalid_argument(oss.str());
            }
        }
    }
}; // class Logger

} //namespace logger

#define __FILENAME__ (std::string(__FILE__).find('/') != std::string::npos? std::string(__FILE__).substr(std::string(__FILE__).rfind('/') + 1) : std::string(__FILE__))

/**
 * LOG macro
 *
 * Synopsis:
 *   LOG(facility, level_spec, sink) << message
 *   LOG(facility, level_spec) << message
 *   LOG(level_spec) << message
 *
 *   `facility`   : string
 *   `level_spec` : integer, string, or logger level
 *   `sink`       : sink ostream
 *
 * Log to `facility` at logger level `level_spec` and dump output to `sink`.
 * If sink is omitted, it defaults to std::clog.
 * If `facility` is omitted (logger has single argument), the macro LOG_FACILITY
 * is used instead, defaulting to "main".
 */

#define __LOG_3(facility, level_spec, sink)                                   \
    { using namespace logger; logger::Logger::thread_local_last_level() = logger::Logger::get_level(level_spec); } \
    if (logger::Logger::thread_local_last_level() > logger::Logger::get_facility_level(facility)) ; \
    else logger::Logger(facility, logger::Logger::thread_local_last_level(), __FILENAME__, __LINE__, __func__, sink).l_value()

#define __LOG_2(facility, level_spec)                                   \
    { using namespace logger; logger::Logger::thread_local_last_level() = logger::Logger::get_level(level_spec); } \
    if (logger::Logger::thread_local_last_level() > logger::Logger::get_facility_level(facility)) ; \
    else logger::Logger(facility, logger::Logger::thread_local_last_level(), __FILENAME__, __LINE__, __func__).l_value()

#define __LOG_1(level_spec) \
    __LOG_2(LOG_FACILITY, level_spec)

// we need 2-level indirection in order to trigger expansion after token pasting
// http://stackoverflow.com/questions/1597007/creating-c-macro-with-and-line-token-concatenation-with-positioning-macr
// http://stackoverflow.com/a/11763196/717706
#ifdef WIN32
#define __EXPAND(...) __VA_ARGS__
#define __LOG_aux2(N, ...) __EXPAND(__LOG_ ## N (__VA_ARGS__))
#else
#define __LOG_aux2(N, ...) __LOG_ ## N (__VA_ARGS__)
#endif

#define __LOG_aux1(N, ...) __LOG_aux2(N, __VA_ARGS__)

#define __NARGS_AUX(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9

#ifdef WIN32
#define __NARGS(...) __EXPAND(__NARGS_AUX(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0))
#else
#define __NARGS(...) __NARGS_AUX(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0)
#endif

#ifndef LOG_FACILITY
#define LOG_FACILITY "main"
#endif

#define LOG(...) __LOG_aux1(__NARGS(__VA_ARGS__), __VA_ARGS__)
#define LOG_EXITCODE(c) logger::Logger((c), __FILENAME__, __LINE__, __func__).l_value()
#define LOG_ABORT LOG_EXITCODE(-1)
#define LOG_EXIT LOG_EXITCODE(EXIT_FAILURE)

#endif

#ifdef SAMPLE_LOGGER

/*

Compile:

g++ -std=c++11 -D SAMPLE_LOGGER -x c++ logger.hpp -o sample-logger

Run:
./sample-logger info
./sample-logger info alt:debug1

*/

using namespace std;

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        cerr << "Use: " << argv[0] << " <log_level_setting> ..." << endl
             << "The program sends 5 log messages with decreasing priority (0=highest, 4=lowest)" << endl
             << "to 2 facilities \"main\" and \"alt\". Command-line arguments are interpreted as" << endl
             << "log facility level settings in the form [<facility>:]<level>." << endl;
        return EXIT_FAILURE;
    }
    for (int i = 1; i < argc; ++i)
    {
        cerr << "processing argument [" << argv[i] << "]" << endl;
        logger::Logger::set_level_from_option(argv[i], &cerr);
    }
    const vector< string > level_name{ "error", "warning", "info", "debug", "debug1", "debug2" };
    for (int l = 0; l < 5; ++l)
    {
        LOG(level_name[l]) << "message at level " << l << " (" << level_name[l]
                           << ") for facility main" << endl;
        LOG("alt", l) << "message at level " << l << " (" << level_name[l]
                      << ") for facility alt" << endl;
    }
}

#endif
<commit_msg>added LOG_THROW<commit_after>/// Part of: https://github.com/mateidavid/hpptools

/// @author    Matei David, Ontario Institute for Cancer Research
/// @version   1.0
/// @date      2013-2017
/// @copyright MIT Public License
///
/// Logger mechanism.
///
/// Properties:
/// - thread-safe, non-garbled output (uses c++11's thread_local)
/// - customizable ostream sink. by default, uses std::clog
///
/// Exports:
/// - "LOG" macro (takes 1, 2, or 3 arguments, see below)
/// - "logger" namespace
/// - "logger::level" enum
/// - "logger::Logger" class
///
/// To use:
/// - In source code, use:
///
///     LOG(info) << "hello" << endl;
///     // or
///     LOG("main", info) << "hello" << endl;
///     // or
///     LOG("main", info, sink_os) << "hello" << endl;
///
///   Here, "main" is the facility (a string) and info is the message level.
///   Note that "logger" is a macro which knows how to look up the name info
///   inside logger namespace. The macro introduces C++ code equivalent to:
///
///     if (...message should be ignored...) then; else sink_os
///
///   NOTE: As with assert(), the code in the output stream following the
///   LOG() macro will ***not be executed*** if the log level of the
///   facility is higher than the level of the message.
///
/// - To set the default log level (for unspecified facilities):
///
///     logger::Logger::set_default_level(logger::Logger::level_from_string(s));
///
/// - To set the log level for the "main" facility:
///
///     logger::Logger::set_facility_level("main", logger::Logger::level_from_string(s));
///
/// - To parse a log facility level setting in the form "[<facility>:]<level>":
///
///     logger::Logger::set_level_from_option("alt:debug1", &cerr);
///
/// - By using these functions, one can set log levels using command-line
///   parameters and achieve dynamic log level settings without recompiling.

#ifndef __LOGGER_HPP
#define __LOGGER_HPP

#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <iostream>
#include <mutex>

namespace logger
{

// log levels
enum level
{
    error = 0,
    warning,
    info,
    debug,
    debug1,
    debug2
};

class Logger
{
public:
    // Constructor: initialize buffer.
    Logger(const std::string& facility, level msg_level,
           const std::string& file_name, unsigned line_num, const std::string& func_name,
           std::ostream& os = std::clog)
        : _os_p(&os), _policy(0)
    {
        _oss << "= " << facility << "." << int(msg_level)
             << " " << file_name << ":" << line_num
             << " " << func_name << " ";
    }
    Logger(int policy, const std::string& file_name, unsigned line_num, const std::string& func_name,
           std::ostream& os = std::cerr)
        : _os_p(&os), _policy(policy)
    {
        _oss << file_name << ":" << line_num
             << " " << func_name << " ";
    }
    // Destructor: dump buffer to output.
    ~Logger() noexcept(false)
    {
        if (_policy == -2) throw std::runtime_error(_oss.str());
        _os_p->write(_oss.str().c_str(), _oss.str().size());
        if (_policy == -1) std::abort();
        if (_policy > 0) std::exit(_policy);
    }
    // Produce l-value for output chaining.
    std::ostream & l_value() { return _oss; }

    // static methods for setting and getting facility log levels.
    static level get_default_level()
    {
        return default_level();
    }
    static void set_default_level(level l)
    {
        static std::mutex m;
        std::lock_guard< std::mutex > lg(m);
        default_level() = l;
    }
    static void set_default_level(int l)
    {
        set_default_level(get_level(l));
    }
    static void set_default_level(const std::string& s)
    {
        set_default_level(get_level(s));
    }
    static level get_facility_level(const std::string& facility)
    {
        return (facility_level_map().count(facility) > 0?
                facility_level_map().at(facility) : get_default_level());
    }
    static void set_facility_level(const std::string& facility, level l)
    {
        static std::mutex m;
        std::lock_guard< std::mutex > lg(m);
        facility_level_map()[facility] = l;
    }
    static void set_facility_level(const std::string& facility, int l)
    {
        set_facility_level(facility, get_level(l));
    }
    static void set_facility_level(const std::string& facility, const std::string& s)
    {
        set_facility_level(facility, get_level(s));
    }
    // static methods for setting log levels from command-line options
    static void set_level_from_option(const std::string& l, std::ostream* os_p = nullptr)
    {
        size_t i = l.find(':');
        if (i == std::string::npos)
        {
            set_default_level(l);
            if (os_p)
            {
                (*os_p) << "set default log level to: "
                        << static_cast< int >(Logger::get_default_level()) << std::endl;
            }
        }
        else
        {
            set_facility_level(l.substr(0, i), l.substr(i + 1));
            if (os_p)
            {
                (*os_p) << "set log level of '" << l.substr(0, i) << "' to: "
                        << static_cast< int >(Logger::get_facility_level(l.substr(0, i))) << std::endl;
            }
        }
    }
    static void set_levels_from_options(const std::vector< std::string >& v, std::ostream* os_p = nullptr)
    {
        for (const auto& l : v)
        {
            set_level_from_option(l, os_p);
        }
    }
    // public static utility functions (used by LOG macro)
    static level get_level(level l) { return l; }
    static level get_level(int i) { return static_cast< level >(i); }
    static level get_level(const std::string& s) { return level_from_string(s); }
    // public static member (used by LOG macro)
    static level& thread_local_last_level()
    {
        static thread_local level _last_level = error;
        return _last_level;
    }
private:
    std::ostringstream _oss;
    // sink for this Logger object
    std::ostream* _os_p;
    int _policy;

    // private static data members
    static level& default_level()
    {
        static level _default_level = error;
        return _default_level;
    }
    static std::map< std::string, level >& facility_level_map()
    {
        static std::map< std::string, level > _facility_level_map;
        return _facility_level_map;
    }
    // private static utility functions
    static level level_from_string(const std::string& s)
    {
        std::istringstream iss(s + "\n");
        int tmp_int = -1;
        iss >> tmp_int;
        if (iss.good())
        {
            return level(tmp_int);
        }
        else
        {
            if (s == "error") return logger::error;
            else if (s == "warning") return logger::warning;
            else if (s == "info") return logger::info;
            else if (s == "debug") return logger::debug;
            else if (s == "debug1") return logger::debug1;
            else if (s == "debug2") return logger::debug2;
            else
            {
                std::ostringstream oss;
                oss << "could not parse log level: " << s;
                throw std::invalid_argument(oss.str());
            }
        }
    }
}; // class Logger

} //namespace logger

#define __FILENAME__ (std::string(__FILE__).find('/') != std::string::npos? std::string(__FILE__).substr(std::string(__FILE__).rfind('/') + 1) : std::string(__FILE__))

/**
 * LOG macro
 *
 * Synopsis:
 *   LOG(facility, level_spec, sink) << message
 *   LOG(facility, level_spec) << message
 *   LOG(level_spec) << message
 *
 *   `facility`   : string
 *   `level_spec` : integer, string, or logger level
 *   `sink`       : sink ostream
 *
 * Log to `facility` at logger level `level_spec` and dump output to `sink`.
 * If sink is omitted, it defaults to std::clog.
 * If `facility` is omitted (logger has single argument), the macro LOG_FACILITY
 * is used instead, defaulting to "main".
 */

#define __LOG_3(facility, level_spec, sink)                                   \
    { using namespace logger; logger::Logger::thread_local_last_level() = logger::Logger::get_level(level_spec); } \
    if (logger::Logger::thread_local_last_level() > logger::Logger::get_facility_level(facility)) ; \
    else logger::Logger(facility, logger::Logger::thread_local_last_level(), __FILENAME__, __LINE__, __func__, sink).l_value()

#define __LOG_2(facility, level_spec)                                   \
    { using namespace logger; logger::Logger::thread_local_last_level() = logger::Logger::get_level(level_spec); } \
    if (logger::Logger::thread_local_last_level() > logger::Logger::get_facility_level(facility)) ; \
    else logger::Logger(facility, logger::Logger::thread_local_last_level(), __FILENAME__, __LINE__, __func__).l_value()

#define __LOG_1(level_spec) \
    __LOG_2(LOG_FACILITY, level_spec)

// we need 2-level indirection in order to trigger expansion after token pasting
// http://stackoverflow.com/questions/1597007/creating-c-macro-with-and-line-token-concatenation-with-positioning-macr
// http://stackoverflow.com/a/11763196/717706
#ifdef WIN32
#define __EXPAND(...) __VA_ARGS__
#define __LOG_aux2(N, ...) __EXPAND(__LOG_ ## N (__VA_ARGS__))
#else
#define __LOG_aux2(N, ...) __LOG_ ## N (__VA_ARGS__)
#endif

#define __LOG_aux1(N, ...) __LOG_aux2(N, __VA_ARGS__)

#define __NARGS_AUX(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9

#ifdef WIN32
#define __NARGS(...) __EXPAND(__NARGS_AUX(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0))
#else
#define __NARGS(...) __NARGS_AUX(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0)
#endif

#ifndef LOG_FACILITY
#define LOG_FACILITY "main"
#endif

#define LOG(...) __LOG_aux1(__NARGS(__VA_ARGS__), __VA_ARGS__)
#define LOG_EXITCODE(c) logger::Logger((c), __FILENAME__, __LINE__, __func__).l_value()
#define LOG_THROW LOG_EXITCODE(-2)
#define LOG_ABORT LOG_EXITCODE(-1)
#define LOG_EXIT  LOG_EXITCODE(EXIT_FAILURE)

#endif

#ifdef SAMPLE_LOGGER

/*

Compile:

g++ -std=c++11 -D SAMPLE_LOGGER -x c++ logger.hpp -o sample-logger

Run:
./sample-logger info
./sample-logger info alt:debug1

*/

using namespace std;

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        cerr << "Use: " << argv[0] << " <log_level_setting> ..." << endl
             << "The program sends 5 log messages with decreasing priority (0=highest, 4=lowest)" << endl
             << "to 2 facilities \"main\" and \"alt\". Command-line arguments are interpreted as" << endl
             << "log facility level settings in the form [<facility>:]<level>." << endl;
        return EXIT_FAILURE;
    }
    for (int i = 1; i < argc; ++i)
    {
        cerr << "processing argument [" << argv[i] << "]" << endl;
        logger::Logger::set_level_from_option(argv[i], &cerr);
    }
    const vector< string > level_name{ "error", "warning", "info", "debug", "debug1", "debug2" };
    for (int l = 0; l < 5; ++l)
    {
        LOG(level_name[l]) << "message at level " << l << " (" << level_name[l]
                           << ") for facility main" << endl;
        LOG("alt", l) << "message at level " << l << " (" << level_name[l]
                      << ") for facility alt" << endl;
    }
}

#endif
<|endoftext|>


<commit_before>// @(#)root/cont
// Author: Philippe Canal Aug 2013

/*************************************************************************
 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TListOfDataMembers                                                   //
//                                                                      //
// A collection of TDataMember objects designed for fast access given a //
// DeclId_t and for keep track of TDataMember that were described       //
// unloaded data member.                                                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TListOfDataMembers.h"
#include "TClass.h"
#include "TExMap.h"
#include "TDataMember.h"
#include "TGlobal.h"
#include "TInterpreter.h"
#include "TVirtualMutex.h"

ClassImp(TListOfDataMembers)

//______________________________________________________________________________
TListOfDataMembers::TListOfDataMembers(TClass *cl) : fClass(cl),fIds(0),fUnloaded(0),fIsLoaded(kFALSE),
                    fLastLoadMarker(0)
{
   // Constructor.

   fIds = new TExMap;
   fUnloaded = new THashList;
}

//______________________________________________________________________________
TListOfDataMembers::~TListOfDataMembers()
{
   // Destructor.

   THashList::Delete();
   delete fIds;
   fUnloaded->Delete();
   delete fUnloaded;
}

//______________________________________________________________________________
void TListOfDataMembers::MapObject(TObject* obj)
{
   // Add a pair<id, object> to the map of data members and their ids.
   if (fClass) {
      TDataMember *d = dynamic_cast<TDataMember*>(obj);
      if (d) {
         fIds->Add((Long64_t)d->GetDeclId(),(Long64_t)d);
      }
   } else {
      TGlobal *g = dynamic_cast<TGlobal*>(obj);
      if (g) {
         fIds->Add((Long64_t)g->GetDeclId(),(Long64_t)g);
      }
   }
}

//______________________________________________________________________________
void TListOfDataMembers::AddFirst(TObject *obj)
{
   // Add object at the beginning of the list.

   THashList::AddFirst(obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddFirst(TObject *obj, Option_t *opt)
{
   // Add object at the beginning of the list and also store option.
   // Storing an option is useful when one wants to change the behaviour
   // of an object a little without having to create a complete new
   // copy of the object. This feature is used, for example, by the Draw()
   // method. It allows the same object to be drawn in different ways.

   THashList::AddFirst(obj,opt);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddLast(TObject *obj)
{
   // Add object at the end of the list.

   THashList::AddLast(obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddLast(TObject *obj, Option_t *opt)
{
   // Add object at the end of the list and also store option.
   // Storing an option is useful when one wants to change the behaviour
   // of an object a little without having to create a complete new
   // copy of the object. This feature is used, for example, by the Draw()
   // method. It allows the same object to be drawn in different ways.

   THashList::AddLast(obj, opt);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddAt(TObject *obj, Int_t idx)
{
   // Insert object at location idx in the list.

   THashList::AddAt(obj, idx);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddAfter(const TObject *after, TObject *obj)
{
   // Insert object after object after in the list.

   THashList::AddAfter(after, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddAfter(TObjLink *after, TObject *obj)
{
   // Insert object after object after in the list.

   THashList::AddAfter(after, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddBefore(const TObject *before, TObject *obj)
{
   // Insert object before object before in the list.

   THashList::AddBefore(before, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddBefore(TObjLink *before, TObject *obj)
{
   // Insert object before object before in the list.

   THashList::AddBefore(before, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::Clear(Option_t *option)
{
   // Remove all objects from the list. Does not delete the objects unless
   // the THashList is the owner (set via SetOwner()).

   fUnloaded->Clear(option);
   fIds->Clear();
   THashList::Clear(option);
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
void TListOfDataMembers::Delete(Option_t *option /* ="" */)
{
   // Delete all TDataMember object files.

   fUnloaded->Delete(option);
   THashList::Delete(option);
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
TObject *TListOfDataMembers::FindObject(const char *name) const
{
   // Specialize FindObject to do search for the
   // a data member just by name or create it if its not already in the list

   TObject *result = THashList::FindObject(name);
   if (!result) {
      TInterpreter::DeclId_t decl;
      if (fClass) decl = gInterpreter->GetDataMember(fClass->GetClassInfo(),name);
      else        decl = gInterpreter->GetDataMember(0,name);
      if (decl) result = const_cast<TListOfDataMembers*>(this)->Get(decl);
   }
   return result;
}

//______________________________________________________________________________
TDictionary *TListOfDataMembers::Get(DeclId_t id)
{
   // Return (after creating it if necessary) the TDataMember
   // describing the data member corresponding to the Decl 'id'.

   if (!id) return 0;

   TDictionary *dm = (TDataMember*)fIds->GetValue((Long64_t)id);
   if (!dm) {
      if (fClass) {
         if (!gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(),id)) return 0;
      } else {
         if (!gInterpreter->ClassInfo_Contains(0,id)) return 0;
      }
      DataMemberInfo_t *info = gInterpreter->DataMemberInfo_Factory(id,fClass ? fClass->GetClassInfo() : 0);

      // Let's see if this is a reload ...
      const char *name = gInterpreter->DataMemberInfo_Name(info);

      TDictionary *update = (TDictionary *)fUnloaded->FindObject(name);
      if (update) {
         if (fClass) {
            ((TDataMember*)update)->Update(info);
         } else {
            ((TGlobal*)update)->Update(info);
         }
         dm = update;
      }
      if (!dm) {
         if (fClass) dm = new TDataMember(info, fClass);
         else dm = new TGlobal(info);
      }
      // Calling 'just' THahList::Add would turn around and call
      // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
      THashList::AddLast(dm);
      fIds->Add((Long64_t)id,(Long64_t)dm);
   }
   return dm;
}

//______________________________________________________________________________
TDictionary *TListOfDataMembers::Get(DataMemberInfo_t *info)
{
   // Return (after creating it if necessary) the TDataMember
   // describing the data member corresponding to the Decl 'id'.

   if (!info) return 0;

   TDictionary::DeclId_t id = gInterpreter->GetDeclId(info);
   TDictionary *dm = (TDataMember*)fIds->GetValue((Long64_t)id);
   if (!dm) {
      if (fClass) {
         if (!gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(),id)) return 0;
      } else {
         if (!gInterpreter->ClassInfo_Contains(0,id)) return 0;
      }

      DataMemberInfo_t *dm_info = gInterpreter->DataMemberInfo_FactoryCopy(info);

      // Let's see if this is a reload ...
      const char *name = gInterpreter->DataMemberInfo_Name(info);
      TDataMember *update = (TDataMember *)fUnloaded->FindObject(name);
      if (update) {
         update->Update(dm_info);
         dm = update;
      }
      if (!dm) {
         if (fClass) dm = new TDataMember(dm_info, fClass);
         else dm = new TGlobal(dm_info);
      }
      // Calling 'just' THahList::Add would turn around and call
      // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
      THashList::AddLast(dm);
      fIds->Add((Long64_t)id,(Long64_t)dm);
   }
   return dm;
}

void TListOfDataMembers::UnmapObject(TObject* obj)
{
   // Remove a pair<id, object> from the map of data members and their ids.
   if (fClass) {
      TDataMember *d = dynamic_cast<TDataMember*>(obj);
      if (d) {
         fIds->Remove((Long64_t)d->GetDeclId());
      }
   } else {
      TGlobal *g = dynamic_cast<TGlobal*>(obj);
      if (g) {
         fIds->Remove((Long64_t)g->GetDeclId());
      }
   }
}

//______________________________________________________________________________
void TListOfDataMembers::RecursiveRemove(TObject *obj)
{
   // Remove object from this collection and recursively remove the object
   // from all other objects (and collections).
   // This function overrides TCollection::RecursiveRemove that calls
   // the Remove function. THashList::Remove cannot be called because
   // it uses the hash value of the hash table. This hash value
   // is not available anymore when RecursiveRemove is called from
   // the TObject destructor.

   if (!obj) return;

   THashList::RecursiveRemove(obj);
   fUnloaded->RecursiveRemove(obj);
   UnmapObject(obj);

}

//______________________________________________________________________________
TObject* TListOfDataMembers::Remove(TObject *obj)
{
   // Remove object from the list.

   Bool_t found;

   found = THashList::Remove(obj);
   if (!found) {
      found = fUnloaded->Remove(obj);
   }
   UnmapObject(obj);
   if (found) return obj;
   else return 0;
}

//______________________________________________________________________________
TObject* TListOfDataMembers::Remove(TObjLink *lnk)
{
   // Remove object via its objlink from the list.

   if (!lnk) return 0;

   TObject *obj = lnk->GetObject();

   THashList::Remove(lnk);
   fUnloaded->Remove(obj);

   UnmapObject(obj);
   return obj;
}

//______________________________________________________________________________
void TListOfDataMembers::Load()
{
   // Load all the DataMembers known to the intepreter for the scope 'fClass'
   // into this collection.

   if (fClass && fClass->GetClassInfo() == 0) return;

   ULong64_t currentTransaction = gInterpreter->GetInterpreterStateMarker();
   if (currentTransaction == fLastLoadMarker) {
      return;
   }
   fLastLoadMarker = currentTransaction;

   if (fClass && fClass->Property() & (kIsClass|kIsStruct|kIsUnion)) {
      // Class and union are not extendable, if we already
      // loaded all the data member there is no need to recheck
      if (fIsLoaded) return;
   }
   // In the case of namespace, even if we have loaded before we need to
   // load again in case there was new data member added.
   // (We may want to avoid doing it if there was no change in the AST).

   // Mark the list as loaded to avoid an infinite recursion in the case
   // where we have a data member that is a variable size array.  In that
   // case TDataMember::Init needs to get/load the list to find the data
   // member used as the array size.
   fIsLoaded = kTRUE;

   ClassInfo_t *info;
   if (fClass) info = fClass->GetClassInfo();
   else info = gInterpreter->ClassInfo_Factory();

   DataMemberInfo_t *t = gInterpreter->DataMemberInfo_Factory(info);
   while (gInterpreter->DataMemberInfo_Next(t)) {
      // if the name cannot be obtained there is no use to put in list
      if (gInterpreter->DataMemberInfo_IsValid(t) && gInterpreter->DataMemberInfo_Name(t)) {
         // Get will check if there is already there or create a new one
         // (or re-use a previously unloaded version).
         Get(t);
      }
   }
   if (!fClass) gInterpreter->ClassInfo_Delete(info);
}

//______________________________________________________________________________
void TListOfDataMembers::Unload()
{
   // Mark 'all func' as being unloaded.
   // After the unload, the data member can no longer be found directly,
   // until the decl can be found again in the interpreter (in which
   // the func object will be reused.

   TObjLink *lnk = FirstLink();
   while (lnk) {
      TDictionary *data = (TDictionary *)lnk->GetObject();
      UnmapObject(data);
      fUnloaded->Add(data);

      lnk = lnk->Next();
   }

   THashList::Clear();
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
void TListOfDataMembers::Unload(TDictionary *mem)
{
   // Mark 'func' as being unloaded.
   // After the unload, the data member can no longer be found directly,
   // until the decl can be found again in the interpreter (in which
   // the func object will be reused.

   if (THashList::Remove(mem)) {
      // We contains the object, let remove it from the other internal
      // list and move it to the list of unloaded objects.

      UnmapObject(mem);
      fUnloaded->Add(mem);
   }
}
<commit_msg>Remove validation of name for TListOf* upon loading the list for speedup.<commit_after>// @(#)root/cont
// Author: Philippe Canal Aug 2013

/*************************************************************************
 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TListOfDataMembers                                                   //
//                                                                      //
// A collection of TDataMember objects designed for fast access given a //
// DeclId_t and for keep track of TDataMember that were described       //
// unloaded data member.                                                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TListOfDataMembers.h"
#include "TClass.h"
#include "TExMap.h"
#include "TDataMember.h"
#include "TGlobal.h"
#include "TInterpreter.h"
#include "TVirtualMutex.h"

ClassImp(TListOfDataMembers)

//______________________________________________________________________________
TListOfDataMembers::TListOfDataMembers(TClass *cl) : fClass(cl),fIds(0),fUnloaded(0),fIsLoaded(kFALSE),
                    fLastLoadMarker(0)
{
   // Constructor.

   fIds = new TExMap;
   fUnloaded = new THashList;
}

//______________________________________________________________________________
TListOfDataMembers::~TListOfDataMembers()
{
   // Destructor.

   THashList::Delete();
   delete fIds;
   fUnloaded->Delete();
   delete fUnloaded;
}

//______________________________________________________________________________
void TListOfDataMembers::MapObject(TObject* obj)
{
   // Add a pair<id, object> to the map of data members and their ids.
   if (fClass) {
      TDataMember *d = dynamic_cast<TDataMember*>(obj);
      if (d) {
         fIds->Add((Long64_t)d->GetDeclId(),(Long64_t)d);
      }
   } else {
      TGlobal *g = dynamic_cast<TGlobal*>(obj);
      if (g) {
         fIds->Add((Long64_t)g->GetDeclId(),(Long64_t)g);
      }
   }
}

//______________________________________________________________________________
void TListOfDataMembers::AddFirst(TObject *obj)
{
   // Add object at the beginning of the list.

   THashList::AddFirst(obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddFirst(TObject *obj, Option_t *opt)
{
   // Add object at the beginning of the list and also store option.
   // Storing an option is useful when one wants to change the behaviour
   // of an object a little without having to create a complete new
   // copy of the object. This feature is used, for example, by the Draw()
   // method. It allows the same object to be drawn in different ways.

   THashList::AddFirst(obj,opt);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddLast(TObject *obj)
{
   // Add object at the end of the list.

   THashList::AddLast(obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddLast(TObject *obj, Option_t *opt)
{
   // Add object at the end of the list and also store option.
   // Storing an option is useful when one wants to change the behaviour
   // of an object a little without having to create a complete new
   // copy of the object. This feature is used, for example, by the Draw()
   // method. It allows the same object to be drawn in different ways.

   THashList::AddLast(obj, opt);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddAt(TObject *obj, Int_t idx)
{
   // Insert object at location idx in the list.

   THashList::AddAt(obj, idx);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddAfter(const TObject *after, TObject *obj)
{
   // Insert object after object after in the list.

   THashList::AddAfter(after, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddAfter(TObjLink *after, TObject *obj)
{
   // Insert object after object after in the list.

   THashList::AddAfter(after, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddBefore(const TObject *before, TObject *obj)
{
   // Insert object before object before in the list.

   THashList::AddBefore(before, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::AddBefore(TObjLink *before, TObject *obj)
{
   // Insert object before object before in the list.

   THashList::AddBefore(before, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfDataMembers::Clear(Option_t *option)
{
   // Remove all objects from the list. Does not delete the objects unless
   // the THashList is the owner (set via SetOwner()).

   fUnloaded->Clear(option);
   fIds->Clear();
   THashList::Clear(option);
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
void TListOfDataMembers::Delete(Option_t *option /* ="" */)
{
   // Delete all TDataMember object files.

   fUnloaded->Delete(option);
   THashList::Delete(option);
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
TObject *TListOfDataMembers::FindObject(const char *name) const
{
   // Specialize FindObject to do search for the
   // a data member just by name or create it if its not already in the list

   TObject *result = THashList::FindObject(name);
   if (!result) {
      TInterpreter::DeclId_t decl;
      if (fClass) decl = gInterpreter->GetDataMember(fClass->GetClassInfo(),name);
      else        decl = gInterpreter->GetDataMember(0,name);
      if (decl) result = const_cast<TListOfDataMembers*>(this)->Get(decl);
   }
   return result;
}

//______________________________________________________________________________
TDictionary *TListOfDataMembers::Get(DeclId_t id)
{
   // Return (after creating it if necessary) the TDataMember
   // describing the data member corresponding to the Decl 'id'.

   if (!id) return 0;

   TDictionary *dm = (TDataMember*)fIds->GetValue((Long64_t)id);
   if (!dm) {
      if (fClass) {
         if (!gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(),id)) return 0;
      } else {
         if (!gInterpreter->ClassInfo_Contains(0,id)) return 0;
      }
      DataMemberInfo_t *info = gInterpreter->DataMemberInfo_Factory(id,fClass ? fClass->GetClassInfo() : 0);

      // Let's see if this is a reload ...
      const char *name = gInterpreter->DataMemberInfo_Name(info);

      TDictionary *update = (TDictionary *)fUnloaded->FindObject(name);
      if (update) {
         if (fClass) {
            ((TDataMember*)update)->Update(info);
         } else {
            ((TGlobal*)update)->Update(info);
         }
         dm = update;
      }
      if (!dm) {
         if (fClass) dm = new TDataMember(info, fClass);
         else dm = new TGlobal(info);
      }
      // Calling 'just' THahList::Add would turn around and call
      // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
      THashList::AddLast(dm);
      fIds->Add((Long64_t)id,(Long64_t)dm);
   }
   return dm;
}

//______________________________________________________________________________
TDictionary *TListOfDataMembers::Get(DataMemberInfo_t *info)
{
   // Return (after creating it if necessary) the TDataMember
   // describing the data member corresponding to the Decl 'id'.

   if (!info) return 0;

   TDictionary::DeclId_t id = gInterpreter->GetDeclId(info);
   TDictionary *dm = (TDataMember*)fIds->GetValue((Long64_t)id);
   if (!dm) {
      if (fClass) {
         if (!gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(),id)) return 0;
      } else {
         if (!gInterpreter->ClassInfo_Contains(0,id)) return 0;
      }

      DataMemberInfo_t *dm_info = gInterpreter->DataMemberInfo_FactoryCopy(info);

      // Let's see if this is a reload ...
      const char *name = gInterpreter->DataMemberInfo_Name(info);
      TDataMember *update = (TDataMember *)fUnloaded->FindObject(name);
      if (update) {
         update->Update(dm_info);
         dm = update;
      }
      if (!dm) {
         if (fClass) dm = new TDataMember(dm_info, fClass);
         else dm = new TGlobal(dm_info);
      }
      // Calling 'just' THahList::Add would turn around and call
      // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
      THashList::AddLast(dm);
      fIds->Add((Long64_t)id,(Long64_t)dm);
   }
   return dm;
}

void TListOfDataMembers::UnmapObject(TObject* obj)
{
   // Remove a pair<id, object> from the map of data members and their ids.
   if (fClass) {
      TDataMember *d = dynamic_cast<TDataMember*>(obj);
      if (d) {
         fIds->Remove((Long64_t)d->GetDeclId());
      }
   } else {
      TGlobal *g = dynamic_cast<TGlobal*>(obj);
      if (g) {
         fIds->Remove((Long64_t)g->GetDeclId());
      }
   }
}

//______________________________________________________________________________
void TListOfDataMembers::RecursiveRemove(TObject *obj)
{
   // Remove object from this collection and recursively remove the object
   // from all other objects (and collections).
   // This function overrides TCollection::RecursiveRemove that calls
   // the Remove function. THashList::Remove cannot be called because
   // it uses the hash value of the hash table. This hash value
   // is not available anymore when RecursiveRemove is called from
   // the TObject destructor.

   if (!obj) return;

   THashList::RecursiveRemove(obj);
   fUnloaded->RecursiveRemove(obj);
   UnmapObject(obj);

}

//______________________________________________________________________________
TObject* TListOfDataMembers::Remove(TObject *obj)
{
   // Remove object from the list.

   Bool_t found;

   found = THashList::Remove(obj);
   if (!found) {
      found = fUnloaded->Remove(obj);
   }
   UnmapObject(obj);
   if (found) return obj;
   else return 0;
}

//______________________________________________________________________________
TObject* TListOfDataMembers::Remove(TObjLink *lnk)
{
   // Remove object via its objlink from the list.

   if (!lnk) return 0;

   TObject *obj = lnk->GetObject();

   THashList::Remove(lnk);
   fUnloaded->Remove(obj);

   UnmapObject(obj);
   return obj;
}

//______________________________________________________________________________
void TListOfDataMembers::Load()
{
   // Load all the DataMembers known to the intepreter for the scope 'fClass'
   // into this collection.

   if (fClass && fClass->GetClassInfo() == 0) return;

   ULong64_t currentTransaction = gInterpreter->GetInterpreterStateMarker();
   if (currentTransaction == fLastLoadMarker) {
      return;
   }
   fLastLoadMarker = currentTransaction;

   if (fClass && fClass->Property() & (kIsClass|kIsStruct|kIsUnion)) {
      // Class and union are not extendable, if we already
      // loaded all the data member there is no need to recheck
      if (fIsLoaded) return;
   }
   // In the case of namespace, even if we have loaded before we need to
   // load again in case there was new data member added.
   // (We may want to avoid doing it if there was no change in the AST).

   // Mark the list as loaded to avoid an infinite recursion in the case
   // where we have a data member that is a variable size array.  In that
   // case TDataMember::Init needs to get/load the list to find the data
   // member used as the array size.
   fIsLoaded = kTRUE;

   ClassInfo_t *info;
   if (fClass) info = fClass->GetClassInfo();
   else info = gInterpreter->ClassInfo_Factory();

   DataMemberInfo_t *t = gInterpreter->DataMemberInfo_Factory(info);
   while (gInterpreter->DataMemberInfo_Next(t)) {
      if (gInterpreter->DataMemberInfo_IsValid(t)) {
         // Get will check if there is already there or create a new one
         // (or re-use a previously unloaded version).
         Get(t);
      }
   }
   if (!fClass) gInterpreter->ClassInfo_Delete(info);
}

//______________________________________________________________________________
void TListOfDataMembers::Unload()
{
   // Mark 'all func' as being unloaded.
   // After the unload, the data member can no longer be found directly,
   // until the decl can be found again in the interpreter (in which
   // the func object will be reused.

   TObjLink *lnk = FirstLink();
   while (lnk) {
      TDictionary *data = (TDictionary *)lnk->GetObject();
      UnmapObject(data);
      fUnloaded->Add(data);

      lnk = lnk->Next();
   }

   THashList::Clear();
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
void TListOfDataMembers::Unload(TDictionary *mem)
{
   // Mark 'func' as being unloaded.
   // After the unload, the data member can no longer be found directly,
   // until the decl can be found again in the interpreter (in which
   // the func object will be reused.

   if (THashList::Remove(mem)) {
      // We contains the object, let remove it from the other internal
      // list and move it to the list of unloaded objects.

      UnmapObject(mem);
      fUnloaded->Add(mem);
   }
}
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief definition of Op
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/gmp_util.hpp>
#include <memory.h>
#include <mcl/array.hpp>

#if defined(__EMSCRIPTEN__) || defined(__wasm__)
	#define MCL_DONT_USE_XBYAK
	#define MCL_DONT_USE_OPENSSL
#endif
#if !defined(MCL_DONT_USE_XBYAK) && (defined(_WIN64) || defined(__x86_64__)) && (MCL_SIZEOF_UNIT == 8) && !defined(MCL_STATIC_CODE)
	#define MCL_USE_XBYAK
#endif
#if defined(MCL_USE_XBYAK) || defined(MCL_STATIC_CODE)
	#define MCL_X64_ASM
	#define MCL_XBYAK_DIRECT_CALL
#endif

#define MCL_MAX_HASH_BIT_SIZE 512

namespace mcl {

static const int version = 0x153; /* 0xABC = A.BC */

/*
	specifies available string format mode for X::setIoMode()
	// for Fp, Fp2, Fp6, Fp12
	default(0) : IoDec
	printable string(zero terminated, variable size)
	IoBin(2) | IoDec(10) | IoHex(16) | IoBinPrefix | IoHexPrefix

	byte string(not zero terminated, fixed size)
	IoArray | IoArrayRaw
	IoArray = IoSerialize

	// for Ec
	affine(0) | IoEcCompY | IoComp
	default : affine

	affine and IoEcCompY are available with ioMode for Fp
	IoSerialize ignores ioMode for Fp

	IoAuto
		dec or hex according to ios_base::fmtflags
	IoBin
		binary number([01]+)
	IoDec
		decimal number
	IoHex
		hexadecimal number([0-9a-fA-F]+)
	IoBinPrefix
		0b + <binary number>
	IoHexPrefix
		0x + <hexadecimal number>
	IoArray
		array of Unit(fixed size = Fp::getByteSize())
	IoArrayRaw
		array of Unit(fixed size = Fp::getByteSize()) without Montgomery conversion

	// for Ec::setIoMode()
	IoEcAffine(default)
	"0" ; infinity
	"1 <x> <y>" ; affine coordinate

	IoEcProj
	"4" <x> <y> <z> ; projective or jacobi coordinate

	IoEcCompY
		1-bit y prepresentation of elliptic curve
		"2 <x>" ; compressed for even y
		"3 <x>" ; compressed for odd y

	IoSerialize
		if isMSBserialize(): // p is not full bit
			size = Fp::getByteSize()
			use MSB of array of x for 1-bit y for prime p where (p % 8 != 0)
			[0] ; infinity
			<x> ; for even y
			<x>|1 ; for odd y ; |1 means set MSB of x
		else:
			size = Fp::getByteSize() + 1
			[0] ; infinity
			2 <x> ; for even y
			3 <x> ; for odd y
*/
enum IoMode {
	IoAuto = 0, // dec or hex according to ios_base::fmtflags
	IoBin = 2, // binary number without prefix
	IoDec = 10, // decimal number without prefix
	IoHex = 16, // hexadecimal number without prefix
	IoArray = 32, // array of Unit(fixed size)
	IoArrayRaw = 64, // raw array of Unit without Montgomery conversion
	IoPrefix = 128, // append '0b'(bin) or '0x'(hex)
	IoBinPrefix = IoBin | IoPrefix,
	IoHexPrefix = IoHex | IoPrefix,
	IoEcAffine = 0, // affine coordinate
	IoEcCompY = 256, // 1-bit y representation of elliptic curve
	IoSerialize = 512, // use MBS for 1-bit y
	IoFixedSizeByteSeq = IoSerialize, // obsolete
	IoEcProj = 1024, // projective or jacobi coordinate
	IoSerializeHexStr = 2048, // printable hex string
	IoEcAffineSerialize = 4096 // serialize [x:y]
};

namespace fp {

inline bool isIoSerializeMode(int ioMode)
{
	return ioMode & (IoArray | IoArrayRaw | IoSerialize | IoEcAffineSerialize | IoSerializeHexStr);
}

const size_t UnitBitSize = sizeof(Unit) * 8;

const size_t maxUnitSize = (MCL_MAX_BIT_SIZE + UnitBitSize - 1) / UnitBitSize;
#define MCL_MAX_UNIT_SIZE ((MCL_MAX_BIT_SIZE + MCL_UNIT_BIT_SIZE - 1) / MCL_UNIT_BIT_SIZE)

const size_t maxMulVecN = 32; // inner loop of mulVec

#ifndef MCL_MAX_MUL_VEC_NGLV
	#define MCL_MAX_MUL_VEC_NGLV 16
#endif
const size_t maxMulVecNGLV = MCL_MAX_MUL_VEC_NGLV; // inner loop of mulVec with GLV

struct FpGenerator;
struct Op;

typedef void (*void1u)(Unit*);
typedef void (*void2u)(Unit*, const Unit*);
typedef void (*void2uI)(Unit*, const Unit*, Unit);
typedef void (*void2uIu)(Unit*, const Unit*, Unit, const Unit*);
typedef void (*void2uOp)(Unit*, const Unit*, const Op&);
typedef void (*void3u)(Unit*, const Unit*, const Unit*);
typedef void (*void4u)(Unit*, const Unit*, const Unit*, const Unit*);
typedef int (*int2u)(Unit*, const Unit*);

typedef Unit (*u1uII)(Unit*, Unit, Unit);
typedef Unit (*u3u)(Unit*, const Unit*, const Unit*);

/*
	disable -Wcast-function-type
	the number of arguments of some JIT functions is smaller than that of T
*/
template<class T, class S>
T func_ptr_cast(S func)
{
	return reinterpret_cast<T>(reinterpret_cast<void*>(func));
}
struct Block {
	const Unit *p; // pointer to original FpT.v_
	size_t n;
	Unit v_[maxUnitSize];
};

enum Mode {
	FP_AUTO,
	FP_GMP,
	FP_GMP_MONT,
	FP_LLVM,
	FP_LLVM_MONT,
	FP_XBYAK
};

enum PrimeMode {
	PM_GENERIC = 0,
	PM_NIST_P192,
	PM_SECP256K1,
	PM_NIST_P521
};

struct Op {
	/*
		don't change the layout of rp and p
		asm code assumes &rp + 1 == p
	*/
	Unit rp;
	Unit p[maxUnitSize];
	mpz_class mp;
	uint32_t pmod4;
	mcl::SquareRoot sq;
	mcl::Modp modp;
	mcl::SmallModp smallModp;
	Unit half[maxUnitSize]; // (p + 1) / 2
	Unit oneRep[maxUnitSize]; // 1(=inv R if Montgomery)
	/*
		for Montgomery
		one = 1
		R = (1 << (N * sizeof(Unit) * 8)) % p
		R2 = (R * R) % p
		R3 = RR^3
	*/
	Unit one[maxUnitSize];
	Unit R2[maxUnitSize];
	Unit R3[maxUnitSize];
#ifdef MCL_USE_XBYAK
	FpGenerator *fg;
#endif
#ifdef MCL_X64_ASM
	mcl::Array<Unit> invTbl;
#endif
	void3u fp_addA_;
	void3u fp_subA_;
	void2u fp_negA_;
	void3u fp_mulA_;
	void2u fp_sqrA_;
	void2u fp_mul2A_;
	void2u fp_mul9A_;
	void3u fp2_addA_;
	void3u fp2_subA_;
	void2u fp2_negA_;
	void3u fp2_mulA_;
	void2u fp2_sqrA_;
	void2u fp2_mul2A_;
	void3u fpDbl_addA_;
	void3u fpDbl_subA_;
	void2u fpDbl_modA_;
	void3u fp2Dbl_mulPreA_;
	void2u fp2Dbl_sqrPreA_;
	void2u fp2Dbl_mul_xiA_;
	size_t maxN;
	size_t N;
	size_t bitSize;
	bool (*fp_isZero)(const Unit*);
	void1u fp_clear;
	void2u fp_copy;
	void2u fp_shr1;
	void3u fp_neg;
	void4u fp_add;
	void4u fp_sub;
	void4u fp_mul;
	void3u fp_sqr;
	void3u fp_mul2;
	void2uOp fp_invOp;
	void2uIu fp_mulUnit; // fpN1_mod + fp_mulUnitPre

	void3u fpDbl_mulPre;
	void2u fpDbl_sqrPre;
	int2u fp_preInv;
	void2uI fp_mulUnitPre; // z[N + 1] = x[N] * y
	void3u fpN1_mod; // y[N] = x[N + 1] % p[N]

	void4u fpDbl_add;
	void4u fpDbl_sub;
	void3u fpDbl_mod;

	u3u fp_addPre; // without modulo p
	u3u fp_subPre; // without modulo p
	u3u fpDbl_addPre;
	u3u fpDbl_subPre;
	/*
		for Fp2 = F[u] / (u^2 + 1)
		x = a + bu
	*/
	int xi_a; // xi = xi_a + u
	void4u fp2_mulNF;
	void2u fp2_mul_xiA_;
	uint32_t (*hash)(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);

	PrimeMode primeMode;
	bool isFullBit; // true if bitSize % uniSize == 0
	bool isMont; // true if use Montgomery
	bool isFastMod; // true if modulo is fast

	Op()
	{
		clear();
	}
	~Op()
	{
#ifdef MCL_USE_XBYAK
		destroyFpGenerator(fg);
#endif
	}
	void clear()
	{
		rp = 0;
		memset(p, 0, sizeof(p));
		mp = 0;
		pmod4 = 0;
		sq.clear();
		// fg is not set
		memset(half, 0, sizeof(half));
		memset(oneRep, 0, sizeof(oneRep));
		memset(one, 0, sizeof(one));
		memset(R2, 0, sizeof(R2));
		memset(R3, 0, sizeof(R3));
#ifdef MCL_X64_ASM
		invTbl.clear();
#endif
		fp_addA_ = 0;
		fp_subA_ = 0;
		fp_negA_ = 0;
		fp_mulA_ = 0;
		fp_sqrA_ = 0;
		fp_mul2A_ = 0;
		fp_mul9A_ = 0;
		fp2_addA_ = 0;
		fp2_subA_ = 0;
		fp2_negA_ = 0;
		fp2_mulA_ = 0;
		fp2_sqrA_ = 0;
		fp2_mul2A_ = 0;
		fpDbl_addA_ = 0;
		fpDbl_subA_ = 0;
		fpDbl_modA_ = 0;
		fp2Dbl_mulPreA_ = 0;
		fp2Dbl_sqrPreA_ = 0;
		fp2Dbl_mul_xiA_ = 0;
		maxN = 0;
		N = 0;
		bitSize = 0;
		fp_isZero = 0;
		fp_clear = 0;
		fp_copy = 0;
		fp_shr1 = 0;
		fp_neg = 0;
		fp_add = 0;
		fp_sub = 0;
		fp_mul = 0;
		fp_sqr = 0;
		fp_mul2 = 0;
		fp_invOp = 0;
		fp_mulUnit = 0;

		fpDbl_mulPre = 0;
		fpDbl_sqrPre = 0;
		fp_preInv = 0;
		fp_mulUnitPre = 0;
		fpN1_mod = 0;

		fpDbl_add = 0;
		fpDbl_sub = 0;
		fpDbl_mod = 0;

		fp_addPre = 0;
		fp_subPre = 0;
		fpDbl_addPre = 0;
		fpDbl_subPre = 0;

		xi_a = 0;
		fp2_mulNF = 0;
		fp2_mul_xiA_ = 0;
		hash = 0;

		primeMode = PM_GENERIC;
		isFullBit = false;
		isMont = false;
		isFastMod = false;
	}
	void fromMont(Unit* y, const Unit *x) const
	{
		/*
			M(x, y) = xyR^-1
			y = M(x, 1) = xR^-1
		*/
		fp_mul(y, x, one, p);
	}
	void toMont(Unit* y, const Unit *x) const
	{
		/*
			y = M(x, R2) = xR^2 R^-1 = xR
		*/
		fp_mul(y, x, R2, p);
	}
	bool init(const mpz_class& p, size_t maxBitSize, int xi_a, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE);
#ifdef MCL_USE_XBYAK
	static FpGenerator* createFpGenerator();
	static void destroyFpGenerator(FpGenerator *fg);
#endif
private:
	Op(const Op&);
	void operator=(const Op&);
};

inline const char* getIoSeparator(int ioMode)
{
	return (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr | IoEcAffineSerialize)) ? "" : " ";
}

inline void dump(const void *buf, size_t n)
{
	const uint8_t *s = (const uint8_t *)buf;
	for (size_t i = 0; i < n; i++) {
		printf("%02x ", s[i]);
	}
	printf("\n");
}

#ifndef CYBOZU_DONT_USE_STRING
int detectIoMode(int ioMode, const std::ios_base& ios);

inline void dump(const std::string& s)
{
	dump(s.c_str(), s.size());
}
#endif

} } // mcl::fp
<commit_msg>v1.54<commit_after>#pragma once
/**
	@file
	@brief definition of Op
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/gmp_util.hpp>
#include <memory.h>
#include <mcl/array.hpp>

#if defined(__EMSCRIPTEN__) || defined(__wasm__)
	#define MCL_DONT_USE_XBYAK
	#define MCL_DONT_USE_OPENSSL
#endif
#if !defined(MCL_DONT_USE_XBYAK) && (defined(_WIN64) || defined(__x86_64__)) && (MCL_SIZEOF_UNIT == 8) && !defined(MCL_STATIC_CODE)
	#define MCL_USE_XBYAK
#endif
#if defined(MCL_USE_XBYAK) || defined(MCL_STATIC_CODE)
	#define MCL_X64_ASM
	#define MCL_XBYAK_DIRECT_CALL
#endif

#define MCL_MAX_HASH_BIT_SIZE 512

namespace mcl {

static const int version = 0x154; /* 0xABC = A.BC */

/*
	specifies available string format mode for X::setIoMode()
	// for Fp, Fp2, Fp6, Fp12
	default(0) : IoDec
	printable string(zero terminated, variable size)
	IoBin(2) | IoDec(10) | IoHex(16) | IoBinPrefix | IoHexPrefix

	byte string(not zero terminated, fixed size)
	IoArray | IoArrayRaw
	IoArray = IoSerialize

	// for Ec
	affine(0) | IoEcCompY | IoComp
	default : affine

	affine and IoEcCompY are available with ioMode for Fp
	IoSerialize ignores ioMode for Fp

	IoAuto
		dec or hex according to ios_base::fmtflags
	IoBin
		binary number([01]+)
	IoDec
		decimal number
	IoHex
		hexadecimal number([0-9a-fA-F]+)
	IoBinPrefix
		0b + <binary number>
	IoHexPrefix
		0x + <hexadecimal number>
	IoArray
		array of Unit(fixed size = Fp::getByteSize())
	IoArrayRaw
		array of Unit(fixed size = Fp::getByteSize()) without Montgomery conversion

	// for Ec::setIoMode()
	IoEcAffine(default)
	"0" ; infinity
	"1 <x> <y>" ; affine coordinate

	IoEcProj
	"4" <x> <y> <z> ; projective or jacobi coordinate

	IoEcCompY
		1-bit y prepresentation of elliptic curve
		"2 <x>" ; compressed for even y
		"3 <x>" ; compressed for odd y

	IoSerialize
		if isMSBserialize(): // p is not full bit
			size = Fp::getByteSize()
			use MSB of array of x for 1-bit y for prime p where (p % 8 != 0)
			[0] ; infinity
			<x> ; for even y
			<x>|1 ; for odd y ; |1 means set MSB of x
		else:
			size = Fp::getByteSize() + 1
			[0] ; infinity
			2 <x> ; for even y
			3 <x> ; for odd y
*/
enum IoMode {
	IoAuto = 0, // dec or hex according to ios_base::fmtflags
	IoBin = 2, // binary number without prefix
	IoDec = 10, // decimal number without prefix
	IoHex = 16, // hexadecimal number without prefix
	IoArray = 32, // array of Unit(fixed size)
	IoArrayRaw = 64, // raw array of Unit without Montgomery conversion
	IoPrefix = 128, // append '0b'(bin) or '0x'(hex)
	IoBinPrefix = IoBin | IoPrefix,
	IoHexPrefix = IoHex | IoPrefix,
	IoEcAffine = 0, // affine coordinate
	IoEcCompY = 256, // 1-bit y representation of elliptic curve
	IoSerialize = 512, // use MBS for 1-bit y
	IoFixedSizeByteSeq = IoSerialize, // obsolete
	IoEcProj = 1024, // projective or jacobi coordinate
	IoSerializeHexStr = 2048, // printable hex string
	IoEcAffineSerialize = 4096 // serialize [x:y]
};

namespace fp {

inline bool isIoSerializeMode(int ioMode)
{
	return ioMode & (IoArray | IoArrayRaw | IoSerialize | IoEcAffineSerialize | IoSerializeHexStr);
}

const size_t UnitBitSize = sizeof(Unit) * 8;

const size_t maxUnitSize = (MCL_MAX_BIT_SIZE + UnitBitSize - 1) / UnitBitSize;
#define MCL_MAX_UNIT_SIZE ((MCL_MAX_BIT_SIZE + MCL_UNIT_BIT_SIZE - 1) / MCL_UNIT_BIT_SIZE)

const size_t maxMulVecN = 32; // inner loop of mulVec

#ifndef MCL_MAX_MUL_VEC_NGLV
	#define MCL_MAX_MUL_VEC_NGLV 16
#endif
const size_t maxMulVecNGLV = MCL_MAX_MUL_VEC_NGLV; // inner loop of mulVec with GLV

struct FpGenerator;
struct Op;

typedef void (*void1u)(Unit*);
typedef void (*void2u)(Unit*, const Unit*);
typedef void (*void2uI)(Unit*, const Unit*, Unit);
typedef void (*void2uIu)(Unit*, const Unit*, Unit, const Unit*);
typedef void (*void2uOp)(Unit*, const Unit*, const Op&);
typedef void (*void3u)(Unit*, const Unit*, const Unit*);
typedef void (*void4u)(Unit*, const Unit*, const Unit*, const Unit*);
typedef int (*int2u)(Unit*, const Unit*);

typedef Unit (*u1uII)(Unit*, Unit, Unit);
typedef Unit (*u3u)(Unit*, const Unit*, const Unit*);

/*
	disable -Wcast-function-type
	the number of arguments of some JIT functions is smaller than that of T
*/
template<class T, class S>
T func_ptr_cast(S func)
{
	return reinterpret_cast<T>(reinterpret_cast<void*>(func));
}
struct Block {
	const Unit *p; // pointer to original FpT.v_
	size_t n;
	Unit v_[maxUnitSize];
};

enum Mode {
	FP_AUTO,
	FP_GMP,
	FP_GMP_MONT,
	FP_LLVM,
	FP_LLVM_MONT,
	FP_XBYAK
};

enum PrimeMode {
	PM_GENERIC = 0,
	PM_NIST_P192,
	PM_SECP256K1,
	PM_NIST_P521
};

struct Op {
	/*
		don't change the layout of rp and p
		asm code assumes &rp + 1 == p
	*/
	Unit rp;
	Unit p[maxUnitSize];
	mpz_class mp;
	uint32_t pmod4;
	mcl::SquareRoot sq;
	mcl::Modp modp;
	mcl::SmallModp smallModp;
	Unit half[maxUnitSize]; // (p + 1) / 2
	Unit oneRep[maxUnitSize]; // 1(=inv R if Montgomery)
	/*
		for Montgomery
		one = 1
		R = (1 << (N * sizeof(Unit) * 8)) % p
		R2 = (R * R) % p
		R3 = RR^3
	*/
	Unit one[maxUnitSize];
	Unit R2[maxUnitSize];
	Unit R3[maxUnitSize];
#ifdef MCL_USE_XBYAK
	FpGenerator *fg;
#endif
#ifdef MCL_X64_ASM
	mcl::Array<Unit> invTbl;
#endif
	void3u fp_addA_;
	void3u fp_subA_;
	void2u fp_negA_;
	void3u fp_mulA_;
	void2u fp_sqrA_;
	void2u fp_mul2A_;
	void2u fp_mul9A_;
	void3u fp2_addA_;
	void3u fp2_subA_;
	void2u fp2_negA_;
	void3u fp2_mulA_;
	void2u fp2_sqrA_;
	void2u fp2_mul2A_;
	void3u fpDbl_addA_;
	void3u fpDbl_subA_;
	void2u fpDbl_modA_;
	void3u fp2Dbl_mulPreA_;
	void2u fp2Dbl_sqrPreA_;
	void2u fp2Dbl_mul_xiA_;
	size_t maxN;
	size_t N;
	size_t bitSize;
	bool (*fp_isZero)(const Unit*);
	void1u fp_clear;
	void2u fp_copy;
	void2u fp_shr1;
	void3u fp_neg;
	void4u fp_add;
	void4u fp_sub;
	void4u fp_mul;
	void3u fp_sqr;
	void3u fp_mul2;
	void2uOp fp_invOp;
	void2uIu fp_mulUnit; // fpN1_mod + fp_mulUnitPre

	void3u fpDbl_mulPre;
	void2u fpDbl_sqrPre;
	int2u fp_preInv;
	void2uI fp_mulUnitPre; // z[N + 1] = x[N] * y
	void3u fpN1_mod; // y[N] = x[N + 1] % p[N]

	void4u fpDbl_add;
	void4u fpDbl_sub;
	void3u fpDbl_mod;

	u3u fp_addPre; // without modulo p
	u3u fp_subPre; // without modulo p
	u3u fpDbl_addPre;
	u3u fpDbl_subPre;
	/*
		for Fp2 = F[u] / (u^2 + 1)
		x = a + bu
	*/
	int xi_a; // xi = xi_a + u
	void4u fp2_mulNF;
	void2u fp2_mul_xiA_;
	uint32_t (*hash)(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);

	PrimeMode primeMode;
	bool isFullBit; // true if bitSize % uniSize == 0
	bool isMont; // true if use Montgomery
	bool isFastMod; // true if modulo is fast

	Op()
	{
		clear();
	}
	~Op()
	{
#ifdef MCL_USE_XBYAK
		destroyFpGenerator(fg);
#endif
	}
	void clear()
	{
		rp = 0;
		memset(p, 0, sizeof(p));
		mp = 0;
		pmod4 = 0;
		sq.clear();
		// fg is not set
		memset(half, 0, sizeof(half));
		memset(oneRep, 0, sizeof(oneRep));
		memset(one, 0, sizeof(one));
		memset(R2, 0, sizeof(R2));
		memset(R3, 0, sizeof(R3));
#ifdef MCL_X64_ASM
		invTbl.clear();
#endif
		fp_addA_ = 0;
		fp_subA_ = 0;
		fp_negA_ = 0;
		fp_mulA_ = 0;
		fp_sqrA_ = 0;
		fp_mul2A_ = 0;
		fp_mul9A_ = 0;
		fp2_addA_ = 0;
		fp2_subA_ = 0;
		fp2_negA_ = 0;
		fp2_mulA_ = 0;
		fp2_sqrA_ = 0;
		fp2_mul2A_ = 0;
		fpDbl_addA_ = 0;
		fpDbl_subA_ = 0;
		fpDbl_modA_ = 0;
		fp2Dbl_mulPreA_ = 0;
		fp2Dbl_sqrPreA_ = 0;
		fp2Dbl_mul_xiA_ = 0;
		maxN = 0;
		N = 0;
		bitSize = 0;
		fp_isZero = 0;
		fp_clear = 0;
		fp_copy = 0;
		fp_shr1 = 0;
		fp_neg = 0;
		fp_add = 0;
		fp_sub = 0;
		fp_mul = 0;
		fp_sqr = 0;
		fp_mul2 = 0;
		fp_invOp = 0;
		fp_mulUnit = 0;

		fpDbl_mulPre = 0;
		fpDbl_sqrPre = 0;
		fp_preInv = 0;
		fp_mulUnitPre = 0;
		fpN1_mod = 0;

		fpDbl_add = 0;
		fpDbl_sub = 0;
		fpDbl_mod = 0;

		fp_addPre = 0;
		fp_subPre = 0;
		fpDbl_addPre = 0;
		fpDbl_subPre = 0;

		xi_a = 0;
		fp2_mulNF = 0;
		fp2_mul_xiA_ = 0;
		hash = 0;

		primeMode = PM_GENERIC;
		isFullBit = false;
		isMont = false;
		isFastMod = false;
	}
	void fromMont(Unit* y, const Unit *x) const
	{
		/*
			M(x, y) = xyR^-1
			y = M(x, 1) = xR^-1
		*/
		fp_mul(y, x, one, p);
	}
	void toMont(Unit* y, const Unit *x) const
	{
		/*
			y = M(x, R2) = xR^2 R^-1 = xR
		*/
		fp_mul(y, x, R2, p);
	}
	bool init(const mpz_class& p, size_t maxBitSize, int xi_a, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE);
#ifdef MCL_USE_XBYAK
	static FpGenerator* createFpGenerator();
	static void destroyFpGenerator(FpGenerator *fg);
#endif
private:
	Op(const Op&);
	void operator=(const Op&);
};

inline const char* getIoSeparator(int ioMode)
{
	return (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr | IoEcAffineSerialize)) ? "" : " ";
}

inline void dump(const void *buf, size_t n)
{
	const uint8_t *s = (const uint8_t *)buf;
	for (size_t i = 0; i < n; i++) {
		printf("%02x ", s[i]);
	}
	printf("\n");
}

#ifndef CYBOZU_DONT_USE_STRING
int detectIoMode(int ioMode, const std::ios_base& ios);

inline void dump(const std::string& s)
{
	dump(s.c_str(), s.size());
}
#endif

} } // mcl::fp
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief definition of Op
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/gmp_util.hpp>
#include <memory.h>
#include <mcl/array.hpp>

#if defined(__EMSCRIPTEN__) || defined(__wasm__)
	#define MCL_DONT_USE_XBYAK
	#define MCL_DONT_USE_OPENSSL
#endif
#if !defined(MCL_DONT_USE_XBYAK) && (defined(_WIN64) || defined(__x86_64__)) && (MCL_SIZEOF_UNIT == 8)
	#define MCL_USE_XBYAK
	#define MCL_XBYAK_DIRECT_CALL
#endif

#define MCL_MAX_HASH_BIT_SIZE 512

namespace mcl {

static const int version = 0x102; /* 0xABC = A.BC */

/*
	specifies available string format mode for X::setIoMode()
	// for Fp, Fp2, Fp6, Fp12
	default(0) : IoDec
	printable string(zero terminated, variable size)
	IoBin(2) | IoDec(10) | IoHex(16) | IoBinPrefix | IoHexPrefix

	byte string(not zero terminated, fixed size)
	IoArray | IoArrayRaw
	IoArray = IoSerialize

	// for Ec
	affine(0) | IoEcCompY | IoComp
	default : affine

	affine and IoEcCompY are available with ioMode for Fp
	IoSerialize ignores ioMode for Fp

	IoAuto
		dec or hex according to ios_base::fmtflags
	IoBin
		binary number([01]+)
	IoDec
		decimal number
	IoHex
		hexadecimal number([0-9a-fA-F]+)
	IoBinPrefix
		0b + <binary number>
	IoHexPrefix
		0x + <hexadecimal number>
	IoArray
		array of Unit(fixed size = Fp::getByteSize())
	IoArrayRaw
		array of Unit(fixed size = Fp::getByteSize()) without Montgomery conversion

	// for Ec::setIoMode()
	IoEcAffine(default)
	"0" ; infinity
	"1 <x> <y>" ; affine coordinate

	IoEcProj
	"4" <x> <y> <z> ; projective or jacobi coordinate

	IoEcCompY
		1-bit y prepresentation of elliptic curve
		"2 <x>" ; compressed for even y
		"3 <x>" ; compressed for odd y

	IoSerialize
		if isMSBserialize(): // p is not full bit
			size = Fp::getByteSize()
			use MSB of array of x for 1-bit y for prime p where (p % 8 != 0)
			[0] ; infinity
			<x> ; for even y
			<x>|1 ; for odd y ; |1 means set MSB of x
		else:
			size = Fp::getByteSize() + 1
			[0] ; infinity
			2 <x> ; for even y
			3 <x> ; for odd y
*/
enum IoMode {
	IoAuto = 0, // dec or hex according to ios_base::fmtflags
	IoBin = 2, // binary number without prefix
	IoDec = 10, // decimal number without prefix
	IoHex = 16, // hexadecimal number without prefix
	IoArray = 32, // array of Unit(fixed size)
	IoArrayRaw = 64, // raw array of Unit without Montgomery conversion
	IoPrefix = 128, // append '0b'(bin) or '0x'(hex)
	IoBinPrefix = IoBin | IoPrefix,
	IoHexPrefix = IoHex | IoPrefix,
	IoEcAffine = 0, // affine coordinate
	IoEcCompY = 256, // 1-bit y representation of elliptic curve
	IoSerialize = 512, // use MBS for 1-bit y
	IoFixedSizeByteSeq = IoSerialize, // obsolete
	IoEcProj = 1024, // projective or jacobi coordinate
	IoSerializeHexStr = 2048 // printable hex string
};

namespace fp {

const size_t UnitBitSize = sizeof(Unit) * 8;

const size_t maxUnitSize = (MCL_MAX_BIT_SIZE + UnitBitSize - 1) / UnitBitSize;
#define MCL_MAX_UNIT_SIZE ((MCL_MAX_BIT_SIZE + MCL_UNIT_BIT_SIZE - 1) / MCL_UNIT_BIT_SIZE)

const size_t maxMulVecN = 32; // inner loop of mulVec
const size_t maxMulVecNGLV = 16; // inner loop of mulVec with GLV

struct FpGenerator;
struct Op;

typedef void (*void1u)(Unit*);
typedef void (*void2u)(Unit*, const Unit*);
typedef void (*void2uI)(Unit*, const Unit*, Unit);
typedef void (*void2uIu)(Unit*, const Unit*, Unit, const Unit*);
typedef void (*void2uOp)(Unit*, const Unit*, const Op&);
typedef void (*void3u)(Unit*, const Unit*, const Unit*);
typedef void (*void4u)(Unit*, const Unit*, const Unit*, const Unit*);
typedef int (*int2u)(Unit*, const Unit*);

typedef Unit (*u1uII)(Unit*, Unit, Unit);
typedef Unit (*u3u)(Unit*, const Unit*, const Unit*);

/*
	disable -Wcast-function-type
	the number of arguments of some JIT functions is smaller than that of T
*/
template<class T, class S>
T func_ptr_cast(S func)
{
	return reinterpret_cast<T>(reinterpret_cast<void*>(func));
}
struct Block {
	const Unit *p; // pointer to original FpT.v_
	size_t n;
	Unit v_[maxUnitSize];
};

enum Mode {
	FP_AUTO,
	FP_GMP,
	FP_GMP_MONT,
	FP_LLVM,
	FP_LLVM_MONT,
	FP_XBYAK
};

enum PrimeMode {
	PM_GENERIC = 0,
	PM_NIST_P192,
	PM_SECP256K1,
	PM_NIST_P521
};

enum MaskMode {
	NoMask = 0, // throw if greater or equal
	SmallMask = 1, // 1-bit smaller mask if greater or equal
	MaskAndMod = 2, // mask and substract if greater or equal
	Mod = 3 // mod p
};

struct Op {
	/*
		don't change the layout of rp and p
		asm code assumes &rp + 1 == p
	*/
	Unit rp;
	Unit p[maxUnitSize];
	mpz_class mp;
	uint32_t pmod4;
	mcl::SquareRoot sq;
	mcl::Modp modp;
	Unit half[maxUnitSize]; // (p + 1) / 2
	Unit oneRep[maxUnitSize]; // 1(=inv R if Montgomery)
	/*
		for Montgomery
		one = 1
		R = (1 << (N * sizeof(Unit) * 8)) % p
		R2 = (R * R) % p
		R3 = RR^3
	*/
	Unit one[maxUnitSize];
	Unit R2[maxUnitSize];
	Unit R3[maxUnitSize];
#ifdef MCL_USE_XBYAK
	FpGenerator *fg;
	mcl::Array<Unit> invTbl;
#endif
	void3u fp_addA_;
	void3u fp_subA_;
	void2u fp_negA_;
	void3u fp_mulA_;
	void2u fp_sqrA_;
	void3u fp2_addA_;
	void3u fp2_subA_;
	void2u fp2_negA_;
	void3u fp2_mulA_;
	void2u fp2_sqrA_;
	void3u fpDbl_addA_;
	void3u fpDbl_subA_;
	void3u fpDbl_mulPreA_;
	void2u fpDbl_sqrPreA_;
	void2u fpDbl_modA_;
	void3u fp2Dbl_mulPreA_;
	void2u fp2Dbl_sqrPreA_;
	size_t maxN;
	size_t N;
	size_t bitSize;
	bool (*fp_isZero)(const Unit*);
	void1u fp_clear;
	void2u fp_copy;
	void2u fp_shr1;
	void3u fp_neg;
	void4u fp_add;
	void4u fp_sub;
	void4u fp_mul;
	void3u fp_sqr;
	void2uOp fp_invOp;
	void2uIu fp_mulUnit; // fpN1_mod + fp_mulUnitPre

	void3u fpDbl_mulPre;
	void2u fpDbl_sqrPre;
	int2u fp_preInv;
	void2uI fp_mulUnitPre; // z[N + 1] = x[N] * y
	void3u fpN1_mod; // y[N] = x[N + 1] % p[N]

	void4u fpDbl_add;
	void4u fpDbl_sub;
	void3u fpDbl_mod;

	u3u fp_addPre; // without modulo p
	u3u fp_subPre; // without modulo p
	u3u fpDbl_addPre;
	u3u fpDbl_subPre;
	/*
		for Fp2 = F[u] / (u^2 + 1)
		x = a + bu
	*/
	int xi_a; // xi = xi_a + u
	void4u fp2_mulNF;
	void2u fp2_inv;
	void2u fp2_mul_xiA_;
	uint32_t (*hash)(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);

	PrimeMode primeMode;
	bool isFullBit; // true if bitSize % uniSize == 0
	bool isMont; // true if use Montgomery
	bool isFastMod; // true if modulo is fast

	Op()
	{
		clear();
	}
	~Op()
	{
#ifdef MCL_USE_XBYAK
		destroyFpGenerator(fg);
#endif
	}
	void clear()
	{
		rp = 0;
		memset(p, 0, sizeof(p));
		mp = 0;
		pmod4 = 0;
		sq.clear();
		// fg is not set
		memset(half, 0, sizeof(half));
		memset(oneRep, 0, sizeof(oneRep));
		memset(one, 0, sizeof(one));
		memset(R2, 0, sizeof(R2));
		memset(R3, 0, sizeof(R3));
#ifdef MCL_USE_XBYAK
		invTbl.clear();
#endif
		fp_addA_ = 0;
		fp_subA_ = 0;
		fp_negA_ = 0;
		fp_mulA_ = 0;
		fp_sqrA_ = 0;
		fp2_addA_ = 0;
		fp2_subA_ = 0;
		fp2_negA_ = 0;
		fp2_mulA_ = 0;
		fp2_sqrA_ = 0;
		fpDbl_addA_ = 0;
		fpDbl_subA_ = 0;
		fpDbl_mulPreA_ = 0;
		fpDbl_sqrPreA_ = 0;
		fpDbl_modA_ = 0;
		fp2Dbl_mulPreA_ = 0;
		fp2Dbl_sqrPreA_ = 0;
		maxN = 0;
		N = 0;
		bitSize = 0;
		fp_isZero = 0;
		fp_clear = 0;
		fp_copy = 0;
		fp_shr1 = 0;
		fp_neg = 0;
		fp_add = 0;
		fp_sub = 0;
		fp_mul = 0;
		fp_sqr = 0;
		fp_invOp = 0;
		fp_mulUnit = 0;

		fpDbl_mulPre = 0;
		fpDbl_sqrPre = 0;
		fp_preInv = 0;
		fp_mulUnitPre = 0;
		fpN1_mod = 0;

		fpDbl_add = 0;
		fpDbl_sub = 0;
		fpDbl_mod = 0;

		fp_addPre = 0;
		fp_subPre = 0;
		fpDbl_addPre = 0;
		fpDbl_subPre = 0;

		xi_a = 0;
		fp2_mulNF = 0;
		fp2_inv = 0;
		fp2_mul_xiA_ = 0;
		hash = 0;

		primeMode = PM_GENERIC;
		isFullBit = false;
		isMont = false;
		isFastMod = false;
	}
	void fromMont(Unit* y, const Unit *x) const
	{
		/*
			M(x, y) = xyR^-1
			y = M(x, 1) = xR^-1
		*/
		fp_mul(y, x, one, p);
	}
	void toMont(Unit* y, const Unit *x) const
	{
		/*
			y = M(x, R2) = xR^2 R^-1 = xR
		*/
		fp_mul(y, x, R2, p);
	}
	bool init(const mpz_class& p, size_t maxBitSize, int xi_a, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE);
#ifdef MCL_USE_XBYAK
	static FpGenerator* createFpGenerator();
	static void destroyFpGenerator(FpGenerator *fg);
#endif
private:
	Op(const Op&);
	void operator=(const Op&);
};

inline const char* getIoSeparator(int ioMode)
{
	return (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr)) ? "" : " ";
}

inline void dump(const void *buf, size_t n)
{
	const uint8_t *s = (const uint8_t *)buf;
	for (size_t i = 0; i < n; i++) {
		printf("%02x ", s[i]);
	}
	printf("\n");
}

#ifndef CYBOZU_DONT_USE_STRING
int detectIoMode(int ioMode, const std::ios_base& ios);

inline void dump(const std::string& s)
{
	dump(s.c_str(), s.size());
}
#endif

} } // mcl::fp
<commit_msg>v1.03<commit_after>#pragma once
/**
	@file
	@brief definition of Op
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/gmp_util.hpp>
#include <memory.h>
#include <mcl/array.hpp>

#if defined(__EMSCRIPTEN__) || defined(__wasm__)
	#define MCL_DONT_USE_XBYAK
	#define MCL_DONT_USE_OPENSSL
#endif
#if !defined(MCL_DONT_USE_XBYAK) && (defined(_WIN64) || defined(__x86_64__)) && (MCL_SIZEOF_UNIT == 8)
	#define MCL_USE_XBYAK
	#define MCL_XBYAK_DIRECT_CALL
#endif

#define MCL_MAX_HASH_BIT_SIZE 512

namespace mcl {

static const int version = 0x103; /* 0xABC = A.BC */

/*
	specifies available string format mode for X::setIoMode()
	// for Fp, Fp2, Fp6, Fp12
	default(0) : IoDec
	printable string(zero terminated, variable size)
	IoBin(2) | IoDec(10) | IoHex(16) | IoBinPrefix | IoHexPrefix

	byte string(not zero terminated, fixed size)
	IoArray | IoArrayRaw
	IoArray = IoSerialize

	// for Ec
	affine(0) | IoEcCompY | IoComp
	default : affine

	affine and IoEcCompY are available with ioMode for Fp
	IoSerialize ignores ioMode for Fp

	IoAuto
		dec or hex according to ios_base::fmtflags
	IoBin
		binary number([01]+)
	IoDec
		decimal number
	IoHex
		hexadecimal number([0-9a-fA-F]+)
	IoBinPrefix
		0b + <binary number>
	IoHexPrefix
		0x + <hexadecimal number>
	IoArray
		array of Unit(fixed size = Fp::getByteSize())
	IoArrayRaw
		array of Unit(fixed size = Fp::getByteSize()) without Montgomery conversion

	// for Ec::setIoMode()
	IoEcAffine(default)
	"0" ; infinity
	"1 <x> <y>" ; affine coordinate

	IoEcProj
	"4" <x> <y> <z> ; projective or jacobi coordinate

	IoEcCompY
		1-bit y prepresentation of elliptic curve
		"2 <x>" ; compressed for even y
		"3 <x>" ; compressed for odd y

	IoSerialize
		if isMSBserialize(): // p is not full bit
			size = Fp::getByteSize()
			use MSB of array of x for 1-bit y for prime p where (p % 8 != 0)
			[0] ; infinity
			<x> ; for even y
			<x>|1 ; for odd y ; |1 means set MSB of x
		else:
			size = Fp::getByteSize() + 1
			[0] ; infinity
			2 <x> ; for even y
			3 <x> ; for odd y
*/
enum IoMode {
	IoAuto = 0, // dec or hex according to ios_base::fmtflags
	IoBin = 2, // binary number without prefix
	IoDec = 10, // decimal number without prefix
	IoHex = 16, // hexadecimal number without prefix
	IoArray = 32, // array of Unit(fixed size)
	IoArrayRaw = 64, // raw array of Unit without Montgomery conversion
	IoPrefix = 128, // append '0b'(bin) or '0x'(hex)
	IoBinPrefix = IoBin | IoPrefix,
	IoHexPrefix = IoHex | IoPrefix,
	IoEcAffine = 0, // affine coordinate
	IoEcCompY = 256, // 1-bit y representation of elliptic curve
	IoSerialize = 512, // use MBS for 1-bit y
	IoFixedSizeByteSeq = IoSerialize, // obsolete
	IoEcProj = 1024, // projective or jacobi coordinate
	IoSerializeHexStr = 2048 // printable hex string
};

namespace fp {

const size_t UnitBitSize = sizeof(Unit) * 8;

const size_t maxUnitSize = (MCL_MAX_BIT_SIZE + UnitBitSize - 1) / UnitBitSize;
#define MCL_MAX_UNIT_SIZE ((MCL_MAX_BIT_SIZE + MCL_UNIT_BIT_SIZE - 1) / MCL_UNIT_BIT_SIZE)

const size_t maxMulVecN = 32; // inner loop of mulVec
const size_t maxMulVecNGLV = 16; // inner loop of mulVec with GLV

struct FpGenerator;
struct Op;

typedef void (*void1u)(Unit*);
typedef void (*void2u)(Unit*, const Unit*);
typedef void (*void2uI)(Unit*, const Unit*, Unit);
typedef void (*void2uIu)(Unit*, const Unit*, Unit, const Unit*);
typedef void (*void2uOp)(Unit*, const Unit*, const Op&);
typedef void (*void3u)(Unit*, const Unit*, const Unit*);
typedef void (*void4u)(Unit*, const Unit*, const Unit*, const Unit*);
typedef int (*int2u)(Unit*, const Unit*);

typedef Unit (*u1uII)(Unit*, Unit, Unit);
typedef Unit (*u3u)(Unit*, const Unit*, const Unit*);

/*
	disable -Wcast-function-type
	the number of arguments of some JIT functions is smaller than that of T
*/
template<class T, class S>
T func_ptr_cast(S func)
{
	return reinterpret_cast<T>(reinterpret_cast<void*>(func));
}
struct Block {
	const Unit *p; // pointer to original FpT.v_
	size_t n;
	Unit v_[maxUnitSize];
};

enum Mode {
	FP_AUTO,
	FP_GMP,
	FP_GMP_MONT,
	FP_LLVM,
	FP_LLVM_MONT,
	FP_XBYAK
};

enum PrimeMode {
	PM_GENERIC = 0,
	PM_NIST_P192,
	PM_SECP256K1,
	PM_NIST_P521
};

enum MaskMode {
	NoMask = 0, // throw if greater or equal
	SmallMask = 1, // 1-bit smaller mask if greater or equal
	MaskAndMod = 2, // mask and substract if greater or equal
	Mod = 3 // mod p
};

struct Op {
	/*
		don't change the layout of rp and p
		asm code assumes &rp + 1 == p
	*/
	Unit rp;
	Unit p[maxUnitSize];
	mpz_class mp;
	uint32_t pmod4;
	mcl::SquareRoot sq;
	mcl::Modp modp;
	Unit half[maxUnitSize]; // (p + 1) / 2
	Unit oneRep[maxUnitSize]; // 1(=inv R if Montgomery)
	/*
		for Montgomery
		one = 1
		R = (1 << (N * sizeof(Unit) * 8)) % p
		R2 = (R * R) % p
		R3 = RR^3
	*/
	Unit one[maxUnitSize];
	Unit R2[maxUnitSize];
	Unit R3[maxUnitSize];
#ifdef MCL_USE_XBYAK
	FpGenerator *fg;
	mcl::Array<Unit> invTbl;
#endif
	void3u fp_addA_;
	void3u fp_subA_;
	void2u fp_negA_;
	void3u fp_mulA_;
	void2u fp_sqrA_;
	void3u fp2_addA_;
	void3u fp2_subA_;
	void2u fp2_negA_;
	void3u fp2_mulA_;
	void2u fp2_sqrA_;
	void3u fpDbl_addA_;
	void3u fpDbl_subA_;
	void3u fpDbl_mulPreA_;
	void2u fpDbl_sqrPreA_;
	void2u fpDbl_modA_;
	void3u fp2Dbl_mulPreA_;
	void2u fp2Dbl_sqrPreA_;
	size_t maxN;
	size_t N;
	size_t bitSize;
	bool (*fp_isZero)(const Unit*);
	void1u fp_clear;
	void2u fp_copy;
	void2u fp_shr1;
	void3u fp_neg;
	void4u fp_add;
	void4u fp_sub;
	void4u fp_mul;
	void3u fp_sqr;
	void2uOp fp_invOp;
	void2uIu fp_mulUnit; // fpN1_mod + fp_mulUnitPre

	void3u fpDbl_mulPre;
	void2u fpDbl_sqrPre;
	int2u fp_preInv;
	void2uI fp_mulUnitPre; // z[N + 1] = x[N] * y
	void3u fpN1_mod; // y[N] = x[N + 1] % p[N]

	void4u fpDbl_add;
	void4u fpDbl_sub;
	void3u fpDbl_mod;

	u3u fp_addPre; // without modulo p
	u3u fp_subPre; // without modulo p
	u3u fpDbl_addPre;
	u3u fpDbl_subPre;
	/*
		for Fp2 = F[u] / (u^2 + 1)
		x = a + bu
	*/
	int xi_a; // xi = xi_a + u
	void4u fp2_mulNF;
	void2u fp2_inv;
	void2u fp2_mul_xiA_;
	uint32_t (*hash)(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);

	PrimeMode primeMode;
	bool isFullBit; // true if bitSize % uniSize == 0
	bool isMont; // true if use Montgomery
	bool isFastMod; // true if modulo is fast

	Op()
	{
		clear();
	}
	~Op()
	{
#ifdef MCL_USE_XBYAK
		destroyFpGenerator(fg);
#endif
	}
	void clear()
	{
		rp = 0;
		memset(p, 0, sizeof(p));
		mp = 0;
		pmod4 = 0;
		sq.clear();
		// fg is not set
		memset(half, 0, sizeof(half));
		memset(oneRep, 0, sizeof(oneRep));
		memset(one, 0, sizeof(one));
		memset(R2, 0, sizeof(R2));
		memset(R3, 0, sizeof(R3));
#ifdef MCL_USE_XBYAK
		invTbl.clear();
#endif
		fp_addA_ = 0;
		fp_subA_ = 0;
		fp_negA_ = 0;
		fp_mulA_ = 0;
		fp_sqrA_ = 0;
		fp2_addA_ = 0;
		fp2_subA_ = 0;
		fp2_negA_ = 0;
		fp2_mulA_ = 0;
		fp2_sqrA_ = 0;
		fpDbl_addA_ = 0;
		fpDbl_subA_ = 0;
		fpDbl_mulPreA_ = 0;
		fpDbl_sqrPreA_ = 0;
		fpDbl_modA_ = 0;
		fp2Dbl_mulPreA_ = 0;
		fp2Dbl_sqrPreA_ = 0;
		maxN = 0;
		N = 0;
		bitSize = 0;
		fp_isZero = 0;
		fp_clear = 0;
		fp_copy = 0;
		fp_shr1 = 0;
		fp_neg = 0;
		fp_add = 0;
		fp_sub = 0;
		fp_mul = 0;
		fp_sqr = 0;
		fp_invOp = 0;
		fp_mulUnit = 0;

		fpDbl_mulPre = 0;
		fpDbl_sqrPre = 0;
		fp_preInv = 0;
		fp_mulUnitPre = 0;
		fpN1_mod = 0;

		fpDbl_add = 0;
		fpDbl_sub = 0;
		fpDbl_mod = 0;

		fp_addPre = 0;
		fp_subPre = 0;
		fpDbl_addPre = 0;
		fpDbl_subPre = 0;

		xi_a = 0;
		fp2_mulNF = 0;
		fp2_inv = 0;
		fp2_mul_xiA_ = 0;
		hash = 0;

		primeMode = PM_GENERIC;
		isFullBit = false;
		isMont = false;
		isFastMod = false;
	}
	void fromMont(Unit* y, const Unit *x) const
	{
		/*
			M(x, y) = xyR^-1
			y = M(x, 1) = xR^-1
		*/
		fp_mul(y, x, one, p);
	}
	void toMont(Unit* y, const Unit *x) const
	{
		/*
			y = M(x, R2) = xR^2 R^-1 = xR
		*/
		fp_mul(y, x, R2, p);
	}
	bool init(const mpz_class& p, size_t maxBitSize, int xi_a, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE);
#ifdef MCL_USE_XBYAK
	static FpGenerator* createFpGenerator();
	static void destroyFpGenerator(FpGenerator *fg);
#endif
private:
	Op(const Op&);
	void operator=(const Op&);
};

inline const char* getIoSeparator(int ioMode)
{
	return (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr)) ? "" : " ";
}

inline void dump(const void *buf, size_t n)
{
	const uint8_t *s = (const uint8_t *)buf;
	for (size_t i = 0; i < n; i++) {
		printf("%02x ", s[i]);
	}
	printf("\n");
}

#ifndef CYBOZU_DONT_USE_STRING
int detectIoMode(int ioMode, const std::ios_base& ios);

inline void dump(const std::string& s)
{
	dump(s.c_str(), s.size());
}
#endif

} } // mcl::fp
<|endoftext|>


<commit_before>#ifndef PACKET_HPP
#define PACKET_HPP

#include <functional>
#include <string>
#include <type_traits>

constexpr uint16_t stringhash(const char* str, int h = 0) {
    return *str ? stringhash(str+1, (h << 1 ^ *str+1)) : h;
}
constexpr uint16_t stringhash(const std::string& str) {
    return stringhash(str.c_str());
}

static uint16_t nextSequenceNum = 1;

//Representing objects as unsigned int is probably the easiest way
//but template is here to allow user to pass any type in the packet
//caution: objects with pointers wont work as data, obviously,
//since memory pointed to by pointers aren't the same across
//machines...
template<class Data = unsigned int>
class Packet {
private:
    uint16_t protocol;
    uint16_t sequence;
    unsigned int datasize;
    unsigned char type;

    //Dont move data any further up - it will cause invalid read of
    //protocol, sequence, type and datasize before the packet was
    //typecasted to the correct type
    Data data;
public:
    constexpr Packet() {}
    constexpr Packet(const unsigned int protocol, unsigned char type, const Data& data, unsigned int datasize) :
        protocol(protocol), sequence(nextSequenceNum++), type(type), data(data), datasize(datasize) {
            static_assert(
                !std::is_pointer<Data>::value,
                "Sending pointers over network can't work. Try to copy the data pointed to by the pointer instead"
            );
        }

    template<class Archive>
    void serialize(Archive& ar) {
        ar(protocol, sequence, datasize, type, data);
    }

    constexpr unsigned int getProtocol() const { return protocol; }
    constexpr unsigned char getSequence() const { return sequence; }
    constexpr unsigned char getType() const { return type; }
    constexpr const Data& getData() const { return data; }
    constexpr Data& getData() { return data; }
    constexpr unsigned int getDataSize() { return datasize; }
};

#endif //PACKET_HPP
<commit_msg>fixed bug where sequencenumber were accidentially casted to char from uint16_t<commit_after>#ifndef PACKET_HPP
#define PACKET_HPP

#include <functional>
#include <string>
#include <type_traits>

constexpr uint16_t stringhash(const char* str, int h = 0) {
    return *str ? stringhash(str+1, (h << 1 ^ *str+1)) : h;
}
constexpr uint16_t stringhash(const std::string& str) {
    return stringhash(str.c_str());
}

static uint16_t nextSequenceNum = 1;

//Representing objects as unsigned int is probably the easiest way
//but template is here to allow user to pass any type in the packet
//caution: objects with pointers wont work as data, obviously,
//since memory pointed to by pointers aren't the same across
//machines...
template<class Data = unsigned int>
class Packet {
private:
    uint16_t protocol;
    uint16_t sequence;
    unsigned int datasize;
    unsigned char type;

    //Dont move data any further up - it will cause invalid read of
    //protocol, sequence, type and datasize before the packet was
    //typecasted to the correct type
    Data data;
public:
    constexpr Packet() {}
    constexpr Packet(const unsigned int protocol, unsigned char type, const Data& data, unsigned int datasize) :
        protocol(protocol), sequence(nextSequenceNum++), type(type), data(data), datasize(datasize) {
            static_assert(
                !std::is_pointer<Data>::value,
                "Sending pointers over network can't work. Try to copy the data pointed to by the pointer instead"
            );
        }

    template<class Archive>
    void serialize(Archive& ar) {
        ar(protocol, sequence, datasize, type, data);
    }

    constexpr uint16_t getProtocol() const { return protocol; }
    constexpr uint16_t getSequence() const { return sequence; }
    constexpr unsigned char getType() const { return type; }
    constexpr const Data& getData() const { return data; }
    constexpr Data& getData() { return data; }
    constexpr unsigned int getDataSize() { return datasize; }
};

#endif //PACKET_HPP
<|endoftext|>