<commit_before>// FONcTransmitter.cc

// This file is part of BES Netcdf File Out Module

// Copyright (c) 2004,2005 University Corporation for Atmospheric Research
// Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact University Corporation for Atmospheric Research at
// 3080 Center Green Drive, Boulder, CO 80301

// (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
// Please read the full copyright statement in the file COPYRIGHT_UCAR.
//
// Authors:
//      pwest       Patrick West <pwest@ucar.edu>
//      jgarcia     Jose Garcia <jgarcia@ucar.edu>

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <sys/types.h>                  // For umask
#include <sys/stat.h>

#include <iostream>
#include <fstream>
#include <exception>

#include <DataDDS.h>
#include <BaseType.h>
#include <escaping.h>
#include <ConstraintEvaluator.h>

#include <BESInternalError.h>
#include <BESDapError.h>
#include <TheBESKeys.h>
#include <BESContextManager.h>
#include <BESDataDDSResponse.h>
#include <BESDapNames.h>
#include <BESDataNames.h>
#include <BESDebug.h>
#include <DapFunctionUtils.h>

#include "FONcBaseType.h"
#include "FONcRequestHandler.h"
#include "FONcTransmitter.h"
#include "FONcTransform.h"

using namespace ::libdap;
using namespace std;

// size of the buffer used to read from the temporary file built on disk and
// send data to the client over the network connection (socket/stream)
#define OUTPUT_FILE_BLOCK_SIZE 4096

/** @brief Construct the FONcTransmitter, adding it with name netcdf to be
 * able to transmit a data response
 *
 * The transmitter is created to add the ability to return OPeNDAP data
 * objects (DataDDS) as a netcdf file.
 *
 * The OPeNDAP data object is written to a netcdf file locally in a
 * temporary directory specified by the BES configuration parameter
 * FONc.Tempdir. If this variable is not found or is not set then it
 * defaults to the macro definition FONC_TEMP_DIR.
 */
FONcTransmitter::FONcTransmitter() :
    BESBasicTransmitter()
{
    add_method(DATA_SERVICE, FONcTransmitter::send_data);
}

#if 0
/**
 * Hack to ensure the file descriptor for the temporary file is closed.
 */
struct wrap_file_descriptor {
    int fd;
    wrap_file_descriptor(int i) : fd(i) { }
    ~wrap_file_descriptor() { cerr << "*** Closing fd" << endl; close(fd); }
};
#endif

/** @brief The static method registered to transmit OPeNDAP data objects as
 * a netcdf file.
 *
 * This function takes the OPeNDAP DataDDS object, reads in the data (can be
 * used with any data handler), transforms the data into a netcdf file, and
 * streams back that netcdf file back to the requester using the stream
 * specified in the BESDataHandlerInterface.
 *
 * @param obj The BESResponseObject containing the OPeNDAP DataDDS object
 * @param dhi BESDataHandlerInterface containing information about the
 * request and response
 * @throws BESInternalError if the response is not an OPeNDAP DataDDS or if
 * there are any problems reading the data, writing to a netcdf file, or
 * streaming the netcdf file
 */
void FONcTransmitter::send_data(BESResponseObject *obj, BESDataHandlerInterface &dhi)
{
    BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(obj);
    if (!bdds) throw BESInternalError("cast error", __FILE__, __LINE__);

    libdap::DataDDS *dds = bdds->get_dds();
    if (!dds) throw BESInternalError("No DataDDS has been created for transmit", __FILE__, __LINE__);

    BESDEBUG("fonc", "FONcTransmitter::send_data() - Parsing the constraint" << endl);

    ConstraintEvaluator &eval = bdds->get_ce();

    string ncVersion = dhi.data[RETURN_CMD];

    ostream &strm = dhi.get_output_stream();
    if (!strm) throw BESInternalError("Output stream is not set, can not return as", __FILE__, __LINE__);

    // ticket 1248 jhrg 2/23/09
    string ce = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
    try {
        eval.parse_constraint(ce, *dds);
    }
    catch (Error &e) {
        throw BESDapError("Failed to parse the constraint expression: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
    }
    catch (...) {
        throw BESInternalError("Failed to parse the constraint expression: Unknown exception caught", __FILE__,
            __LINE__);
    }

    // The dataset_name is no longer used in the constraint evaluator, so no
    // need to get here. Plus, just getting the first container's dataset
    // name would not have worked with multiple containers.
    // pwest Jan 4, 2009
    // string dataset_name = "";

    // now we need to read the data
    BESDEBUG("fonc", "FONcTransmitter::send_data() - Reading data into DataDDS" << endl);

    // ADB: remember when we're using a temp DDS
    // bool using_temp_dds = false; See comment below about set_dds(). jhrg 8/8/14

    try {
        // Handle *functional* constraint expressions specially
        if (eval.function_clauses()) {
            BESDEBUG("fonc", "FONcTransmitter::send_data() - Processing functional constraint clause(s)." << endl);
            DataDDS *tmp_dds = eval.eval_function_clauses(*dds);
            delete dds;
            dds = tmp_dds;
            bdds->set_dds(dds);

            // This next step utilizes a well known function, promote_function_output_structures()
            // to look for one or more top level Structures whose name indicates (by way of ending
            // with "_uwrap") that their contents should be promoted (aka moved) to the top level.
            // This is in support of a hack around the current API where server side functions
            // may only return a single DAP object and not a collection of objects. The name suffix
            // "_unwrap" is used as a signal from the function to the the various response
            // builders and transmitters that the representation needs to be altered before
            // transmission, and that in fact is what happens in our friend
            // promote_function_output_structures()
            promote_function_output_structures(dds);

        }
        else {
            // Iterate through the variables in the DataDDS and read
            // in the data if the variable has the send flag set.

            for (DDS::Vars_iter i = dds->var_begin(); i != dds->var_end(); i++) {
                if ((*i)->send_p()) {
                    BESDEBUG("fonc", "FONcTransmitter::send_data() - Interning data for variable: '" << (*i)->name() << "'" << endl);
                    (*i)->intern_data(eval, *dds);
                }
            }
        }
    }
    catch (Error &e) {
        throw BESDapError("Failed to read data: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
    }
    catch (BESError &e) {
        throw;
    }
    catch (std::exception &e) {
        throw BESInternalError("Failed to read data: STL Error: " + string(e.what()), __FILE__, __LINE__);
    }
    catch (...) {
        throw BESInternalError("Failed to read data. Unknown Error", __FILE__, __LINE__);
    }

    //string temp_file_name = FONcTransmitter::temp_dir + '/' + "ncXXXXXX";
    string temp_file_name = FONcRequestHandler::temp_dir + '/' + "ncXXXXXX";
    vector<char> temp_full(temp_file_name.length() + 1);
    string::size_type len = temp_file_name.copy(&temp_full[0], temp_file_name.length());
    temp_full[len] = '\0';
    // cover the case where older versions of mkstemp() create the file using
    // a mode of 666.
    mode_t original_mode = umask(077);
    int fd = mkstemp(&temp_full[0]);
    umask(original_mode);
#if 0
    // Trick: We can unlink the file right here - it will persist until the file descriptor
    // is closed. This means we don't have to litter the code with call to unlink(). jhrg 11/25/15
    (void) unlink(&temp_full[0]);
    // Hack: Use this simple class to 'wrap' the file descriptor so that we can be sure it
    // is closed no matter how this code is exited. jhrg 11/25/15
    wrap_file_descriptor wrapped_fd(fd);
#endif
    if (fd == -1) throw BESInternalError("Failed to open the temporary file: " + temp_file_name, __FILE__, __LINE__);

    // transform the OPeNDAP DataDDS to the netcdf file
    BESDEBUG("fonc", "FONcTransmitter::send_data - Transforming into temporary file: " << &temp_full[0] << endl);

    try {
        FONcTransform ft(dds, dhi, &temp_full[0], ncVersion);
        ft.transform();

        BESDEBUG("fonc", "FONcTransmitter::send_data - Transmitting temp file " << &temp_full[0] << endl);
        FONcTransmitter::return_temp_stream(&temp_full[0], strm, ncVersion);
    }
    catch (Error &e) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw BESDapError("Failed to Transform data to NetCDF: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
    }
    catch (BESError &e) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw;
    }
    catch (std::exception &e) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw BESInternalError("Failed to Transform data to NetCDF: STL Error: " + string(e.what()), __FILE__, __LINE__);
    }
    catch (...) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw BESInternalError("Failed to Transform data to NetCDF. Unknown Error", __FILE__, __LINE__);
    }

    (void) unlink(&temp_full[0]);
    close(fd);

    BESDEBUG("fonc", "FONcTransmitter::send_data - done transmitting to netcdf" << endl);
}

/** @brief stream the temporary netcdf file back to the requester
 *
 * Streams the temporary netcdf file specified by filename to the specified
 * C++ ostream
 *
 * @param filename The name of the file to stream back to the requester
 * @param strm C++ ostream to write the contents of the file to
 * @throws BESInternalError if problem opening the file
 */
void FONcTransmitter::return_temp_stream(const string &filename, ostream &strm, const string &ncVersion)
{
    ifstream os;
    os.open(filename.c_str(), ios::binary | ios::in);
    if (!os)
        throw BESInternalError("Fileout netcdf: Cannot connect to netcdf file.", __FILE__, __LINE__);;

    char block[OUTPUT_FILE_BLOCK_SIZE];

    os.read(block, sizeof block);
    int nbytes = os.gcount();
    if (nbytes > 0) {
        bool found = false;
        string context = "transmit_protocol";
        string protocol = BESContextManager::TheManager()->get_context(context, found);
        if (protocol == "HTTP") {
            strm << "HTTP/1.0 200 OK\n";
            strm << "Content-type: application/octet-stream\n";
            strm << "Content-Description: " << "BES dataset" << "\n";
            if (ncVersion == RETURNAS_NETCDF4) {
                strm << "Content-Disposition: filename=" << filename << ".nc4;\n\n";
            }
            else {
                strm << "Content-Disposition: filename=" << filename << ".nc;\n\n";
            }
            strm << flush;
        }
        strm.write(block, nbytes);
    }
    else {
        // close the stream before we leave.
        os.close();
        throw BESInternalError("Fileout netcdf: Failed to stream the response back to the client, got zero count on stream buffer.", __FILE__, __LINE__);
    }

    while (os) {
        os.read(block, sizeof block);
        strm.write(block, os.gcount());
    }

    os.close();
}

<commit_msg>Added first draft of history attribute machinery.<commit_after>// FONcTransmitter.cc

// This file is part of BES Netcdf File Out Module

// Copyright (c) 2004,2005 University Corporation for Atmospheric Research
// Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact University Corporation for Atmospheric Research at
// 3080 Center Green Drive, Boulder, CO 80301

// (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
// Please read the full copyright statement in the file COPYRIGHT_UCAR.
//
// Authors:
//      pwest       Patrick West <pwest@ucar.edu>
//      jgarcia     Jose Garcia <jgarcia@ucar.edu>

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <sys/types.h>                  // For umask
#include <sys/stat.h>

#include <iostream>
#include <fstream>
#include <exception>
#include <sstream>      // std::stringstream

#include <DataDDS.h>
#include <BaseType.h>
#include <escaping.h>
#include <ConstraintEvaluator.h>

#include <BESInternalError.h>
#include <BESDapError.h>
#include <TheBESKeys.h>
#include <BESContextManager.h>
#include <BESDataDDSResponse.h>
#include <BESDapNames.h>
#include <BESDataNames.h>
#include <BESDebug.h>
#include <DapFunctionUtils.h>

#include "FONcBaseType.h"
#include "FONcRequestHandler.h"
#include "FONcTransmitter.h"
#include "FONcTransform.h"

using namespace ::libdap;
using namespace std;

// size of the buffer used to read from the temporary file built on disk and
// send data to the client over the network connection (socket/stream)
#define OUTPUT_FILE_BLOCK_SIZE 4096

/** @brief Construct the FONcTransmitter, adding it with name netcdf to be
 * able to transmit a data response
 *
 * The transmitter is created to add the ability to return OPeNDAP data
 * objects (DataDDS) as a netcdf file.
 *
 * The OPeNDAP data object is written to a netcdf file locally in a
 * temporary directory specified by the BES configuration parameter
 * FONc.Tempdir. If this variable is not found or is not set then it
 * defaults to the macro definition FONC_TEMP_DIR.
 */
FONcTransmitter::FONcTransmitter() :
    BESBasicTransmitter()
{
    add_method(DATA_SERVICE, FONcTransmitter::send_data);
}

#if 0
/**
 * Hack to ensure the file descriptor for the temporary file is closed.
 */
struct wrap_file_descriptor {
    int fd;
    wrap_file_descriptor(int i) : fd(i) { }
    ~wrap_file_descriptor() { cerr << "*** Closing fd" << endl; close(fd); }
};
#endif

/**
 * Process the "history" attribute.
 * We add:
 *  - Sub-setting information if any
 *  - SSFunction invocations
 *  - ResourceID? URL?
 */
void updateHistoryAttribute(DDS *dds){

    string hyrax_version =  "Hyrax-1.13.1";
    string request_url   =  "http://gosuckanegg.com";

    std::stringstream new_history_entry;

    time_t raw_now;
    struct tm * timeinfo;
    time(&raw_now);  /* get current time; same as: timer = time(NULL)  */
    timeinfo = localtime (&raw_now);

    char time_str[100];
    // 2000-6-1 6:00:00
    strftime(time_str,100,"%Y-%m-%d %H:%M:%S",timeinfo);

    new_history_entry << time_str << " "<< hyrax_version << " " << request_url;
    vector<string> hist_entry_vec;
    hist_entry_vec.push_back(new_history_entry.str());

    BESDEBUG("fonc", "FONcTransmitter::updateHistoryAttribute() - new_history_entry: '" << new_history_entry.str() << "'" << endl);

    // Add the new entry to the "history" attribute
    // Get the top level Attribute table.
    AttrTable &globals = dds->get_attr_table();

    // Since many files support "CF" conventions the history tag may already exist in the source data
    // and we should add an entry to it if possible.
    bool done = false; // Used to indicate that we located a toplevel ATtrTable whose name ends in "_GLOBAL" and that has an existing "history" attribute.
    unsigned int num_attrs = globals.get_size();
    if (num_attrs) {
        // Here we look for a top level AttrTable whose name ends with "_GLOBAL" which is where, by convention,
        // data ingest handlers place global level attributes found in the source dataset.
        AttrTable::Attr_iter i = globals.attr_begin();
        AttrTable::Attr_iter e = globals.attr_end();
        for (; i != e && !done; i++) {
            AttrType attrType = globals.get_attr_type(i);
            string attr_name = globals.get_name(i);
            // Test the entry...
            if (attrType==Attr_container && BESUtil::endsWith(attr_name, "_GLOBAL")) {
                // Look promising, but does it have an existing "history" Attribute?
                AttrTable *source_file_globals = globals.get_attr_table(i);
                AttrTable::Attr_iter history_attrItr = source_file_globals->simple_find("history");
                if(history_attrItr != source_file_globals->attr_end()){
                    // Yup! Add our entry...
                    BESDEBUG("fonc", "FONcTransmitter::updateHistoryAttribute() - Adding history entry to " << attr_name << endl);
                    source_file_globals->append_attr("history", "string", &hist_entry_vec);
                    done = true;
                }
            }
        }
    }

    if(!done){
        // We never found an existing location to place the "history" entry, so we'll just stuff it into the top level AttrTable.
        BESDEBUG("fonc", "FONcTransmitter::updateHistoryAttribute() - Adding history entry to top level AttrTable" << endl);
        globals.append_attr("history", "string", &hist_entry_vec);

    }

#if 0

    // SIMPLE FIRST DRAFT

    // ###########
    // The following should be rewritten to add the history to any global
    // attribute table who's name ends in _GLOBAL and that already has a history attr.
    // because people use CF in hdf4, hdf5, nc, etc.
    // . . . . . .
    // Since we know that the contents NC_GLOBAL AttrTable will be promoted to global level attributes in the resulting   nectdf file
    // we check for an existing history attribute there and add the new entry if we find the history attr there.
     AttrTable *nc_global_attrT = globals.simple_find_container("NC_GLOBAL");
    // Is there an NC_GLOBAL attribute table.
    if(nc_global_attrT){
        // If we found an NC_GLOBAL attribute table, append our "history" attribute to it.
        BESDEBUG("fonc", "FONcTransmitter::updateHistoryAttribute() - Adding history entry to NC_GLOBAL" << endl);
        nc_global_attrT->append_attr("history", "string", &hist_entry_vec);
    }
    else {

        // If we don't have an NC_GLOBAL attribute table just append it to the global table.
        // Other wise we just add it to the top level where it belongs.
        BESDEBUG("fonc", "FONcTransmitter::updateHistoryAttribute() - Adding history entry to top level AttrTable" << endl);
        globals.append_attr("history", "string", &hist_entry_vec);

    }
    // ###########
#endif
}

/** @brief The static method registered to transmit OPeNDAP data objects as
 * a netcdf file.
 *
 * This function takes the OPeNDAP DataDDS object, reads in the data (can be
 * used with any data handler), transforms the data into a netcdf file, and
 * streams back that netcdf file back to the requester using the stream
 * specified in the BESDataHandlerInterface.
 *
 * @param obj The BESResponseObject containing the OPeNDAP DataDDS object
 * @param dhi BESDataHandlerInterface containing information about the
 * request and response
 * @throws BESInternalError if the response is not an OPeNDAP DataDDS or if
 * there are any problems reading the data, writing to a netcdf file, or
 * streaming the netcdf file
 */
void FONcTransmitter::send_data(BESResponseObject *obj, BESDataHandlerInterface &dhi)
{
    BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(obj);
    if (!bdds) throw BESInternalError("cast error", __FILE__, __LINE__);

    libdap::DataDDS *dds = bdds->get_dds();
    if (!dds) throw BESInternalError("No DataDDS has been created for transmit", __FILE__, __LINE__);

    BESDEBUG("fonc", "FONcTransmitter::send_data() - Parsing the constraint" << endl);

    ConstraintEvaluator &eval = bdds->get_ce();

    string ncVersion = dhi.data[RETURN_CMD];

    ostream &strm = dhi.get_output_stream();
    if (!strm) throw BESInternalError("Output stream is not set, can not return as", __FILE__, __LINE__);

    // ticket 1248 jhrg 2/23/09
    string ce = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
    try {
        eval.parse_constraint(ce, *dds);
    }
    catch (Error &e) {
        throw BESDapError("Failed to parse the constraint expression: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
    }
    catch (...) {
        throw BESInternalError("Failed to parse the constraint expression: Unknown exception caught", __FILE__,
            __LINE__);
    }

    // The dataset_name is no longer used in the constraint evaluator, so no
    // need to get here. Plus, just getting the first container's dataset
    // name would not have worked with multiple containers.
    // pwest Jan 4, 2009
    // string dataset_name = "";

    // now we need to read the data
    BESDEBUG("fonc", "FONcTransmitter::send_data() - Reading data into DataDDS" << endl);

    // ADB: remember when we're using a temp DDS
    // bool using_temp_dds = false; See comment below about set_dds(). jhrg 8/8/14

    try {
        // Handle *functional* constraint expressions specially
        if (eval.function_clauses()) {
            BESDEBUG("fonc", "FONcTransmitter::send_data() - Processing functional constraint clause(s)." << endl);
            DataDDS *tmp_dds = eval.eval_function_clauses(*dds);
            delete dds;
            dds = tmp_dds;
            bdds->set_dds(dds);

            // This next step utilizes a well known function, promote_function_output_structures()
            // to look for one or more top level Structures whose name indicates (by way of ending
            // with "_uwrap") that their contents should be promoted (aka moved) to the top level.
            // This is in support of a hack around the current API where server side functions
            // may only return a single DAP object and not a collection of objects. The name suffix
            // "_unwrap" is used as a signal from the function to the the various response
            // builders and transmitters that the representation needs to be altered before
            // transmission, and that in fact is what happens in our friend
            // promote_function_output_structures()
            promote_function_output_structures(dds);

        }
        else {
            // Iterate through the variables in the DataDDS and read
            // in the data if the variable has the send flag set.

            for (DDS::Vars_iter i = dds->var_begin(); i != dds->var_end(); i++) {
                if ((*i)->send_p()) {
                    BESDEBUG("fonc", "FONcTransmitter::send_data() - Interning data for variable: '" << (*i)->name() << "'" << endl);
                    (*i)->intern_data(eval, *dds);
                }
            }
        }
    }
    catch (Error &e) {
        throw BESDapError("Failed to read data: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
    }
    catch (BESError &e) {
        throw;
    }
    catch (std::exception &e) {
        throw BESInternalError("Failed to read data: STL Error: " + string(e.what()), __FILE__, __LINE__);
    }
    catch (...) {
        throw BESInternalError("Failed to read data. Unknown Error", __FILE__, __LINE__);
    }

    updateHistoryAttribute(dds);

    //string temp_file_name = FONcTransmitter::temp_dir + '/' + "ncXXXXXX";
    string temp_file_name = FONcRequestHandler::temp_dir + '/' + "ncXXXXXX";
    vector<char> temp_full(temp_file_name.length() + 1);
    string::size_type len = temp_file_name.copy(&temp_full[0], temp_file_name.length());
    temp_full[len] = '\0';
    // cover the case where older versions of mkstemp() create the file using
    // a mode of 666.
    mode_t original_mode = umask(077);
    int fd = mkstemp(&temp_full[0]);
    umask(original_mode);
#if 0
    // Trick: We can unlink the file right here - it will persist until the file descriptor
    // is closed. This means we don't have to litter the code with call to unlink(). jhrg 11/25/15
    (void) unlink(&temp_full[0]);
    // Hack: Use this simple class to 'wrap' the file descriptor so that we can be sure it
    // is closed no matter how this code is exited. jhrg 11/25/15
    wrap_file_descriptor wrapped_fd(fd);
#endif
    if (fd == -1) throw BESInternalError("Failed to open the temporary file: " + temp_file_name, __FILE__, __LINE__);

    // transform the OPeNDAP DataDDS to the netcdf file
    BESDEBUG("fonc", "FONcTransmitter::send_data - Transforming into temporary file: " << &temp_full[0] << endl);

    try {
        FONcTransform ft(dds, dhi, &temp_full[0], ncVersion);
        ft.transform();

        BESDEBUG("fonc", "FONcTransmitter::send_data - Transmitting temp file " << &temp_full[0] << endl);
        FONcTransmitter::return_temp_stream(&temp_full[0], strm, ncVersion);
    }
    catch (Error &e) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw BESDapError("Failed to Transform data to NetCDF: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
    }
    catch (BESError &e) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw;
    }
    catch (std::exception &e) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw BESInternalError("Failed to Transform data to NetCDF: STL Error: " + string(e.what()), __FILE__, __LINE__);
    }
    catch (...) {
        (void) unlink(&temp_full[0]);
        close(fd);
        throw BESInternalError("Failed to Transform data to NetCDF. Unknown Error", __FILE__, __LINE__);
    }

    (void) unlink(&temp_full[0]);
    close(fd);

    BESDEBUG("fonc", "FONcTransmitter::send_data - done transmitting to netcdf" << endl);
}

/** @brief stream the temporary netcdf file back to the requester
 *
 * Streams the temporary netcdf file specified by filename to the specified
 * C++ ostream
 *
 * @param filename The name of the file to stream back to the requester
 * @param strm C++ ostream to write the contents of the file to
 * @throws BESInternalError if problem opening the file
 */
void FONcTransmitter::return_temp_stream(const string &filename, ostream &strm, const string &ncVersion)
{
    ifstream os;
    os.open(filename.c_str(), ios::binary | ios::in);
    if (!os)
        throw BESInternalError("Fileout netcdf: Cannot connect to netcdf file.", __FILE__, __LINE__);;

    char block[OUTPUT_FILE_BLOCK_SIZE];

    os.read(block, sizeof block);
    int nbytes = os.gcount();
    if (nbytes > 0) {
        bool found = false;
        string context = "transmit_protocol";
        string protocol = BESContextManager::TheManager()->get_context(context, found);
        if (protocol == "HTTP") {
            strm << "HTTP/1.0 200 OK\n";
            strm << "Content-type: application/octet-stream\n";
            strm << "Content-Description: " << "BES dataset" << "\n";
            if (ncVersion == RETURNAS_NETCDF4) {
                strm << "Content-Disposition: filename=" << filename << ".nc4;\n\n";
            }
            else {
                strm << "Content-Disposition: filename=" << filename << ".nc;\n\n";
            }
            strm << flush;
        }
        strm.write(block, nbytes);
    }
    else {
        // close the stream before we leave.
        os.close();
        throw BESInternalError("Fileout netcdf: Failed to stream the response back to the client, got zero count on stream buffer.", __FILE__, __LINE__);
    }

    while (os) {
        os.read(block, sizeof block);
        strm.write(block, os.gcount());
    }

    os.close();
}

<|endoftext|>


<commit_before>/*
Rozbuduj poprzeni program o operacje modyfikujące elementy tablicy.
Po każdej operacji wypisz tablicę na ekran:
- odwracanie kolejności elementów tablicy
- przesunięcie tablicy w prawo
(element na pozycji 0 jest przesuwany na pozycję 1,
element na pozycji 1 jest przesuwany na pozycję numer 2, itd.
Ostatni element jest wstawiany na pozycję 0)
- sortowanie tablicy (uporządkowanie elementów rosnąco)
*/

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <utility>

#define SIZE 10

using std::cout;
using std::endl;

int main() {

	int tab[SIZE];
	srand(time(NULL));

    cout << "Tablica: ";
	for (int i = 0; i < SIZE; i++) {
		tab[i] = rand() % 100;
		cout << tab[i] << " ";
	}
    cout << endl;

    for (int i = 0; i < SIZE / 2; i++) {
        //int t = tab[SIZE - i - 1];
        //tab[SIZE - i - 1] = tab[i];
        //tab[i] = t;
        std::swap(tab[SIZE - i - 1], tab[i]);
    }

    cout << "Tablica odwrócona: ";
    for (int i = 0; i < SIZE; i++) {
        cout << tab[i] << " ";
    }
    cout << endl;

    int t{0};
    for (int i = 0; i < SIZE; i++) {
        if (i + 1 == SIZE) {
            tab[0] = tab[SIZE - 1];
            tab[SIZE - 1] = t;
        } else {
            int r = tab[i];
            tab[i] = t;
            t = r;
        }
    }

    cout << "Tablica przesunięta w prawo: ";
    for (int i = 0; i < SIZE; i++) {
        cout << tab[i] << " ";
    }
    cout << endl;

}
<commit_msg>sortowanie bąbelkowe<commit_after>/*
Rozbuduj poprzeni program o operacje modyfikujące elementy tablicy.
Po każdej operacji wypisz tablicę na ekran:
- odwracanie kolejności elementów tablicy
- przesunięcie tablicy w prawo
(element na pozycji 0 jest przesuwany na pozycję 1,
element na pozycji 1 jest przesuwany na pozycję numer 2, itd.
Ostatni element jest wstawiany na pozycję 0)
- sortowanie tablicy (uporządkowanie elementów rosnąco)
*/

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <utility>

#define SIZE 10

using std::cout;
using std::endl;

int main() {

	int tab[SIZE];
	srand(time(NULL));

    cout << "Tablica: ";
	for (int i = 0; i < SIZE; i++) {
		tab[i] = rand() % 100;
		cout << tab[i] << " ";
	}
    cout << endl;

    for (int i = 0; i < SIZE / 2; i++) {
        //int t = tab[SIZE - i - 1];
        //tab[SIZE - i - 1] = tab[i];
        //tab[i] = t;
        std::swap(tab[SIZE - i - 1], tab[i]);
    }

    cout << "Tablica odwrócona: ";
    for (int i = 0; i < SIZE; i++) {
        cout << tab[i] << " ";
    }
    cout << endl;

    int t{0};
    for (int i = 0; i < SIZE; i++) {
        if (i + 1 == SIZE) {
            tab[0] = tab[SIZE - 1];
            tab[SIZE - 1] = t;
        } else {
            int r = tab[i];
            tab[i] = t;
            t = r;
        }
    }

    cout << "Tablica przesunięta w prawo: ";
    for (int i = 0; i < SIZE; i++) {
        cout << tab[i] << " ";
    }
    cout << endl;

    /*
    procedure bubbleSort( A : lista elementów do posortowania )
	n = liczba_elementów(A)
	do
		for (i = 0; i < n-1; i++) do:
			if A[i] > A[i+1] then
				swap(A[i], A[i+1])
			end if
		end for
		n = n-1
	while n > 1
	end procedure
	*/
    int n = SIZE;
    do {
		for (int i = 0; i < n-1; i++) {
			if (tab[i] > tab[i+1]) {
				//std::swap(tab[i], tab[i+1]);
				int c = tab[i];
				tab[i] = tab[i+1];
				tab[i+1] = c;
			}
		}
		n--;
	} while (n > 1);

	cout << "Tablica posortowana: ";
	for (int i = 0; i < SIZE; i++) {
        cout << tab[i] << " ";
    }
    cout << endl;

}

<|endoftext|>


<commit_before>/*
  Copyright (c) 2014-2015 DataStax

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#ifdef STAND_ALONE
#   define BOOST_TEST_MODULE cassandra
#endif

#include <algorithm>

#if !defined(WIN32) && !defined(_WIN32)
#include <signal.h>
#endif

#include "cassandra.h"
#include "testing.hpp"
#include "test_utils.hpp"
#include "cql_ccm_bridge.hpp"

#include <boost/test/unit_test.hpp>
#include <boost/test/debug.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/cstdint.hpp>
#include <boost/format.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/thread/future.hpp>
#include <boost/bind.hpp>
#include <boost/chrono.hpp>
#include <boost/cstdint.hpp>

#include <map>
#include <set>
#include <string>

BOOST_AUTO_TEST_SUITE(custom_payload)

BOOST_AUTO_TEST_CASE(simple)
{
  test_utils::CassClusterPtr cluster(cass_cluster_new());

  const cql::cql_ccm_bridge_configuration_t& conf = cql::get_ccm_bridge_configuration();
  boost::shared_ptr<cql::cql_ccm_bridge_t> ccm = cql::cql_ccm_bridge_t::create(conf, "test");

  ccm->add_node(1);
  ccm->start(1, "-Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler");

  CassVersion version = ccm->version();
  BOOST_REQUIRE((version.major >= 2 && version.minor >= 2) || version.major >= 3);

  test_utils::initialize_contact_points(cluster.get(), conf.ip_prefix(), 1, 0);

  test_utils::CassSessionPtr session(test_utils::create_session(cluster.get()));

  test_utils::CassStatementPtr statement(cass_statement_new("SELECT * FROM system.local", 0));

  test_utils::CassCustomPayloadPtr custom_payload(cass_custom_payload_new());

  typedef std::map<std::string, std::string> PayloadItemMap;

  PayloadItemMap items;
  items["key1"] = "value1";
  items["key2"] = "value2";
  items["key3"] = "value3";

  for (PayloadItemMap::const_iterator i = items.begin(); i != items.end(); ++i) {
    cass_custom_payload_set(custom_payload.get(),
                            i->first.c_str(),
                            reinterpret_cast<const cass_byte_t*>(i->second.data()), i->second.size());
  }

  cass_statement_set_custom_payload(statement.get(), custom_payload.get());

  test_utils::CassFuturePtr future(cass_session_execute(session.get(), statement.get()));

  size_t item_count = cass_future_custom_payload_item_count(future.get());

  BOOST_REQUIRE(item_count == items.size());

  for (size_t i = 0; i < item_count; ++i) {
    const char* name;
    size_t name_length;
    const cass_byte_t* value;
    size_t value_size;
    BOOST_REQUIRE(cass_future_custom_payload_item(future.get(), i,
                                                  &name, &name_length,
                                                  &value, &value_size) == CASS_OK);

    PayloadItemMap::const_iterator it = items.find(std::string(name, name_length));
    BOOST_REQUIRE(it != items.end());
    BOOST_CHECK_EQUAL(it->second, std::string(reinterpret_cast<const char*>(value), value_size));
  }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Removing unused includes and limiting test to run with C* 2.2+<commit_after>/*
  Copyright (c) 2014-2015 DataStax

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#ifdef STAND_ALONE
#   define BOOST_TEST_MODULE cassandra
#endif

#include "cassandra.h"
#include "test_utils.hpp"
#include "cql_ccm_bridge.hpp"

#include <boost/test/unit_test.hpp>
#include <boost/test/debug.hpp>

#include <map>
#include <set>
#include <string>

BOOST_AUTO_TEST_SUITE(custom_payload)

BOOST_AUTO_TEST_CASE(simple)
{
  const cql::cql_ccm_bridge_configuration_t& conf = cql::get_ccm_bridge_configuration();
  CassVersion version(conf.cassandara_version());
  if ((version.major >= 2 && version.minor >= 2) || version.major >= 3) {
    boost::debug::detect_memory_leaks(false);
    boost::shared_ptr<cql::cql_ccm_bridge_t> ccm = cql::cql_ccm_bridge_t::create(conf, "test");

    ccm->populate(1);
    ccm->start(1, "-Dcassandra.custom_query_handler_class=org.apache.cassandra.cql3.CustomPayloadMirroringQueryHandler");

    test_utils::CassClusterPtr cluster(cass_cluster_new());
    test_utils::initialize_contact_points(cluster.get(), conf.ip_prefix(), 1, 0);

    test_utils::CassSessionPtr session(test_utils::create_session(cluster.get()));

    test_utils::CassStatementPtr statement(cass_statement_new("SELECT * FROM system.local", 0));

    test_utils::CassCustomPayloadPtr custom_payload(cass_custom_payload_new());

    typedef std::map<std::string, std::string> PayloadItemMap;

    PayloadItemMap items;
    items["key1"] = "value1";
    items["key2"] = "value2";
    items["key3"] = "value3";

    for (PayloadItemMap::const_iterator i = items.begin(); i != items.end(); ++i) {
      cass_custom_payload_set(custom_payload.get(),
                              i->first.c_str(),
                              reinterpret_cast<const cass_byte_t*>(i->second.data()), i->second.size());
    }

    cass_statement_set_custom_payload(statement.get(), custom_payload.get());

    test_utils::CassFuturePtr future(cass_session_execute(session.get(), statement.get()));

    size_t item_count = cass_future_custom_payload_item_count(future.get());

    BOOST_REQUIRE(item_count == items.size());

    for (size_t i = 0; i < item_count; ++i) {
      const char* name;
      size_t name_length;
      const cass_byte_t* value;
      size_t value_size;
      BOOST_REQUIRE(cass_future_custom_payload_item(future.get(), i,
                                                    &name, &name_length,
                                                    &value, &value_size) == CASS_OK);

      PayloadItemMap::const_iterator it = items.find(std::string(name, name_length));
      BOOST_REQUIRE(it != items.end());
      BOOST_CHECK_EQUAL(it->second, std::string(reinterpret_cast<const char*>(value), value_size));
    }
  } else {
    boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages);
    BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping custom_payload/simple");
    BOOST_REQUIRE(true);
  }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_CHECK_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_CHECK_HPP

#include "traits.hpp"
#include "function_traits.hpp"
#include "construct_function.hpp"
#include "override_traits.hpp"

namespace kgr {
namespace detail {

/*
 * Trait that check if the service definition can be constructed given the return type of it's construct function.
 */
template<typename T, typename... Args>
struct is_service_constructible_helper {
private:
	template<typename U, typename... As, std::size_t F, std::size_t... S>
	static is_service_instantiable<T,
		tuple_element_t<F, function_result_t<construct_function_t<U, As...>>>,
		tuple_element_t<S, function_result_t<construct_function_t<U, As...>>>...> test(seq<F, S...>);

	// This overload is needed for msvc.
	// Or else it will try to call the one just above with a 0 as S for strange reason.
	template<typename U, typename... As, int_t<construct_function_t<U, As...>> = 0>
	static is_service_instantiable<T> test(seq<>);

	template<typename U, typename... As, enable_if_t<is_supplied_service<U>::value || !has_any_construct<U, As...>::value, int> = 0>
	static std::true_type test_helper(int);

	template<typename...>
	static std::false_type test(...);

	template<typename...>
	static std::false_type test_helper(...);

	// The enable if is required here or else the function call will be ambiguous on visual studio.
	template<typename U, typename... As, enable_if_t<!is_supplied_service<U>::value && has_any_construct<U, As...>::value, int> = 0>
	static auto test_helper(int) -> decltype(test<U, As...>(tuple_seq<function_result_t<construct_function_t<U, As...>>>{}));

public:
	using type = decltype(test_helper<T, Args...>(0));
};

/*
 * Alias for is_service_constructible_helper
 */
template<typename T, typename... Args>
using is_service_constructible = typename is_service_constructible_helper<T, Args...>::type;

/*
 * Meta trait that applies a trait recursively for each dependencies and thier dependencies.
 */
template<template<typename...> class Trait, typename T, typename... Args>
struct dependency_trait {
	template<typename... Service>
	struct service_check_dependencies : conjunction<
		Trait<detected_t<injected_service_t, Service>>...,
		dependency_trait<Trait, detected_t<injected_service_t, Service>, Args...>...
	> {};

	static constexpr bool value =
		is_supplied_service<T>::value ||
		expand_n<
			safe_minus(detected_or<std::integral_constant<int, 0>, meta_list_size, detected_or<meta_list<>, function_arguments_t, detected_t<construct_function_t, T, Args...>>>::value, sizeof...(Args)),
			detected_or<meta_list<>, function_arguments_t, detected_t<construct_function_t, T, Args...>>,
			service_check_dependencies
		>::value;
};

/*
 * Validity check for default services
 */
template<typename T>
using is_default_service_valid = std::integral_constant<bool,
	(is_abstract_service<T>::value || !has_default<T>::value) &&
	is_default_overrides_abstract<T>::value &&
	is_default_convertible<T>::value
>;

template<typename T>
using is_abstract_not_final = std::integral_constant<bool,
	!is_abstract_service<T>::value || !is_final_service<T>::value
>;

/*
 * Validity check for a service, without it's dependencies
 */
template<typename T, typename... Args>
using shallow_service_check = std::integral_constant<bool,
	is_service<T>::value &&
	is_service_constructible<T, Args...>::value &&
	is_construct_function_callable<T, Args...>::value &&
	is_default_service_valid<T>::value &&
	is_override_convertible<T>::value &&
	is_override_polymorphic<T>::value &&
	is_override_services<T>::value &&
	is_override_not_final<T>::value &&
	is_abstract_not_final<T>::value
>;

/*
 * Validity check for dependencies of a service
 */
template<typename T, typename... Args>
using dependency_check = dependency_trait<shallow_service_check, T, Args...>;

template<typename T, typename... Args>
struct service_check : bool_constant<
	shallow_service_check<T, Args...>::value && dependency_check<T, Args...>::value
> {};

} // namespace detail
} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_CHECK_HPP
<commit_msg>Made dependency_trait work with both the latest visual studio and visual studio 2015<commit_after>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_CHECK_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_CHECK_HPP

#include "traits.hpp"
#include "function_traits.hpp"
#include "construct_function.hpp"
#include "override_traits.hpp"

namespace kgr {
namespace detail {

#ifndef KGR_KANGARU_MSVC_DEPENDENCY_TRAIT_STRUCT
#if _MSC_VER == 1900
#ifndef __clang__
// MSVC has a defect that makes the use of the template keyword an error in some corner cases.
#define KGR_KANGARU_MSVC_DEPENDENCY_TRAIT_STRUCT
#endif // !__clang__
#endif // _MSC_VER
#endif // KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD

/*
 * Trait that check if the service definition can be constructed given the return type of it's construct function.
 */
template<typename T, typename... Args>
struct is_service_constructible_helper {
private:
	template<typename U, typename... As, std::size_t F, std::size_t... S>
	static is_service_instantiable<T,
		tuple_element_t<F, function_result_t<construct_function_t<U, As...>>>,
		tuple_element_t<S, function_result_t<construct_function_t<U, As...>>>...> test(seq<F, S...>);

	// This overload is needed for msvc.
	// Or else it will try to call the one just above with a 0 as S for strange reason.
	template<typename U, typename... As, int_t<construct_function_t<U, As...>> = 0>
	static is_service_instantiable<T> test(seq<>);

	template<typename U, typename... As, enable_if_t<is_supplied_service<U>::value || !has_any_construct<U, As...>::value, int> = 0>
	static std::true_type test_helper(int);

	template<typename...>
	static std::false_type test(...);

	template<typename...>
	static std::false_type test_helper(...);

	// The enable if is required here or else the function call will be ambiguous on visual studio.
	template<typename U, typename... As, enable_if_t<!is_supplied_service<U>::value && has_any_construct<U, As...>::value, int> = 0>
	static auto test_helper(int) -> decltype(test<U, As...>(tuple_seq<function_result_t<construct_function_t<U, As...>>>{}));

public:
	using type = decltype(test_helper<T, Args...>(0));
};

/*
 * Alias for is_service_constructible_helper
 */
template<typename T, typename... Args>
using is_service_constructible = typename is_service_constructible_helper<T, Args...>::type;

/*
 * Meta trait that applies a trait recursively for each dependencies and thier dependencies.
 */
template<template<typename...> class Trait, typename T, typename... Args>
struct dependency_trait {
	template<typename... Service>
	struct service_check_dependencies {
		static constexpr bool value = conjunction<
			Trait<detected_t<injected_service_t, Service>>...,
			dependency_trait<Trait, detected_t<injected_service_t, Service>, Args...>...
		>::value;
	};

	static constexpr bool value =
		is_supplied_service<T>::value ||
		expand_n<
			safe_minus(detected_or<std::integral_constant<int, 0>, meta_list_size, detected_or<meta_list<>, function_arguments_t, detected_t<construct_function_t, T, Args...>>>::value, sizeof...(Args)),
			detected_or<meta_list<>, function_arguments_t, detected_t<construct_function_t, T, Args...>>,
			service_check_dependencies
		>::value;
};

/*
 * Validity check for default services
 */
template<typename T>
using is_default_service_valid = std::integral_constant<bool,
	(is_abstract_service<T>::value || !has_default<T>::value) &&
	is_default_overrides_abstract<T>::value &&
	is_default_convertible<T>::value
>;

template<typename T>
using is_abstract_not_final = std::integral_constant<bool,
	!is_abstract_service<T>::value || !is_final_service<T>::value
>;

/*
 * Validity check for a service, without it's dependencies
 */
template<typename T, typename... Args>
using shallow_service_check = std::integral_constant<bool,
	is_service<T>::value &&
	is_service_constructible<T, Args...>::value &&
	is_construct_function_callable<T, Args...>::value &&
	is_default_service_valid<T>::value &&
	is_override_convertible<T>::value &&
	is_override_polymorphic<T>::value &&
	is_override_services<T>::value &&
	is_override_not_final<T>::value &&
	is_abstract_not_final<T>::value
>;

/*
 * Validity check for dependencies of a service
 */
template<typename T, typename... Args>
using dependency_check = dependency_trait<shallow_service_check, T, Args...>;

template<typename T, typename... Args>
struct service_check : bool_constant<
	shallow_service_check<T, Args...>::value && dependency_check<T, Args...>::value
> {};

} // namespace detail
} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_CHECK_HPP
<|endoftext|>


<commit_before>// Copyright 2016-2020 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef MPPP_DETAIL_INTEGER_LITERALS_HPP
#define MPPP_DETAIL_INTEGER_LITERALS_HPP

#include <cassert>
#include <cstddef>
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>

#include <mp++/config.hpp>
#include <mp++/detail/gmp.hpp>
#include <mp++/detail/utils.hpp>

namespace mppp
{

namespace detail
{

// Helper to check if an integral literal is valid.
// It will return the base of the literal. Supported
// bases are 2, 8, 10 and 16.
// NOTE: we need this function in the C++11/C++14 implementation
// as well, so use MPPP_CONSTEXPR_14, MPPP_FALLTHROUGH, etc.
template <std::size_t Size>
inline
#if !defined(_MSC_VER) || defined(__clang__)
    MPPP_CONSTEXPR_14
#endif
    int
    integer_literal_check_str(const char (&arr)[Size])
{
    // We expect the size of the array to be
    // always at least 2, the null terminator
    // plus at least one char from the literal.
    static_assert(Size >= 2u, "Invalid array size.");
#if MPPP_CPLUSPLUS >= 201703L
    assert(arr[Size - 1u] == '\0');
#endif

    // The actual string length of the literal.
    constexpr auto str_length = Size - 1u;

    // Helpers to check a digit in various bases.
    auto base10_digit_check = [&arr](char c) {
        if (c < '0' || c > '9') {
            throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
        }
    };

    auto base8_digit_check = [&arr](char c) {
        if (c < '0' || c > '7') {
            throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
        }
    };

    auto base2_digit_check = [&arr](char c) {
        if (c != '0' && c != '1') {
            throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
        }
    };

    auto base16_digit_check = [&arr](char c) {
        if (c < '0' || c > '9') {
            switch (c) {
                case 'a':
                    MPPP_FALLTHROUGH;
                case 'b':
                    MPPP_FALLTHROUGH;
                case 'c':
                    MPPP_FALLTHROUGH;
                case 'd':
                    MPPP_FALLTHROUGH;
                case 'e':
                    MPPP_FALLTHROUGH;
                case 'f':
                    MPPP_FALLTHROUGH;
                case 'A':
                    MPPP_FALLTHROUGH;
                case 'B':
                    MPPP_FALLTHROUGH;
                case 'C':
                    MPPP_FALLTHROUGH;
                case 'D':
                    MPPP_FALLTHROUGH;
                case 'E':
                    MPPP_FALLTHROUGH;
                case 'F':
                    return;
                default:
                    throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
            }
        }
    };

    if (str_length == 1u) {
        // If the string length is 1, the only
        // character must be in the ['0', '9'] range.
        base10_digit_check(arr[0]);

        // NOTE: the literal "0" is actually an
        // octal, but it does not matter if we
        // construct it using base 10.
        return 10;
    }

    // The string length is at least 2. Infer the base
    // of the literal.
    const int base = [&arr, base8_digit_check, base10_digit_check]() -> int {
        // Fetch the first 2 digits.
        const auto d0 = arr[0], d1 = arr[1];

        if (d0 == '0') {
            // Binary, octal or hex.
            if (d1 == 'b' || d1 == 'B') {
                return 2;
            } else if (d1 == 'x' || d1 == 'X') {
                return 16;
            } else {
                base8_digit_check(d1);
                return 8;
            }
        } else {
            // Decimal.
            base10_digit_check(d0);
            base10_digit_check(d1);
            return 10;
        }
    }();

#if MPPP_CPLUSPLUS >= 201703L
    assert(base == 2 || base == 8 || base == 10 || base == 16);
#endif

    // Run the checks on the rest of the literal,
    // after we already checked the first 2 digits.
    // For bases 2 and 16, we need to have other digits,
    // otherwise the literal is malformed.
    // NOLINTNEXTLINE(hicpp-multiway-paths-covered)
    switch (base) {
        case 2:
            if (str_length == 2u) {
                throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
            }
            for (std::size_t i = 2; i < str_length; ++i) {
                base2_digit_check(arr[i]);
            }
            break;
        case 8:
            for (std::size_t i = 2; i < str_length; ++i) {
                base8_digit_check(arr[i]);
            }
            break;
        case 10:
            for (std::size_t i = 2; i < str_length; ++i) {
                base10_digit_check(arr[i]);
            }
            break;
        case 16:
            if (str_length == 2u) {
                throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
            }
            for (std::size_t i = 2; i < str_length; ++i) {
                base16_digit_check(arr[i]);
            }
    }

    return base;
}

#if MPPP_CPLUSPLUS >= 201703L && (!defined(_MSC_VER) || defined(__clang__))

// Small helper to convert the char representation
// of a digit into the corresponding numerical
// value for a given Base. Base must be one
// of 2, 8, 10 or 16, and Int must be some integral
// type.
template <int Base, typename Int>
constexpr Int digit_to_value(char c)
{
    static_assert(std::is_integral_v<Int>);
    static_assert(Base == 2 || Base == 8 || Base == 10 || Base == 16);

    if constexpr (Base == 16) {
        if (c >= '0' && c <= '9') {
            return static_cast<Int>(c - '0');
        } else {
            switch (c) {
                case 'a':
                    [[fallthrough]];
                case 'A':
                    return static_cast<Int>(10);
                case 'b':
                    [[fallthrough]];
                case 'B':
                    return static_cast<Int>(11);
                case 'c':
                    [[fallthrough]];
                case 'C':
                    return static_cast<Int>(12);
                case 'd':
                    [[fallthrough]];
                case 'D':
                    return static_cast<Int>(13);
                case 'e':
                    [[fallthrough]];
                case 'E':
                    return static_cast<Int>(14);
                default:
                    assert(c == 'f' || c == 'F');
                    return static_cast<Int>(15);
            }
        }
    } else {
        if constexpr (Base == 2) {
            assert(c == '0' || c == '1');
        } else if constexpr (Base == 8) {
            assert(c >= '0' && c <= '7');
        } else {
            assert(c >= '0' && c <= '9');
        }
        return static_cast<Int>(c - '0');
    }
}

#endif

template <std::size_t SSize, char... Chars>
inline integer<SSize> integer_literal_impl()
{
    // Turn the sequence of input chars
    // into a null-terminated char array.
    // NOTE: earlier clang versions won't properly
    // capture arr in the lambdas below if it is
    // not marked as static.
#if defined(__clang__) && __clang_major__ <= 5
    static
#endif
        constexpr char arr[]
        = {Chars..., '\0'};

#if MPPP_CPLUSPLUS >= 201703L && (!defined(_MSC_VER) || defined(__clang__)) && !defined(__INTEL_COMPILER)
    // Run the checks on the char sequence, and determine the base.
    constexpr auto base = integer_literal_check_str(arr);
    static_assert(base == 2 || base == 8 || base == 10 || base == 16);

    // The actual number of digits in the literal
    // (discounting prefixes).
    constexpr auto ndigits = (base == 2 || base == 16) ? (sizeof...(Chars) - 2u)
                                                       : (base == 8 ? (sizeof...(Chars) - 1u) : sizeof...(Chars));

    // Determine how many digits in the given base we can always fit
    // into a single mp_limb_t.
    constexpr auto nd_limb = static_cast<unsigned>([]() {
        [[maybe_unused]] constexpr auto nbits = std::numeric_limits<::mp_limb_t>::digits;

        if constexpr (base == 2) {
            // Base 2, just return the number of bits.
            return nbits;
        } else if constexpr (base == 8) {
            // Base 8, need 3 bits per digit.
            return nbits / 3;
        } else if constexpr (base == 16) {
            // Base 16, need 4 bits per digit.
            return nbits / 4;
        } else {
            // Base 10, use digits10.
            return std::numeric_limits<::mp_limb_t>::digits10;
        }
    }());

    // Determine how many instances of mp_limb_t we need
    // to represent the literal.
    constexpr auto nlimbs = ndigits / nd_limb + static_cast<unsigned>(ndigits % nd_limb != 0u);
    static_assert(nlimbs > 0u);

    // Helper function to parse a single limb from a subset
    // of digits at indices [begin, end) in the literal.
    auto parse_limb = [](std::size_t begin, std::size_t end) {
        ::mp_limb_t retval = 0, shifter = 1;

        for (auto i = end; i > begin; --i) {
            const auto cur_digit = digit_to_value<base, ::mp_limb_t>(arr[i - 1u]);
            retval += cur_digit * shifter;

            if (i > begin + 1u) {
                // If this is not the last iteration, update the shifter.
                shifter *= static_cast<::mp_limb_t>(base);
            }
        }

        return retval;
    };

    if constexpr (nlimbs == 1u) {
        // Fast path if the literal fits into
        // a single mp_limb_t.
        constexpr auto l = parse_limb(sizeof...(Chars) - ndigits, sizeof...(Chars));

        return integer<SSize>{l};
    } else {
        // The literal needs more than 1 limb:
        // build an array of limbs from the literal
        // and use it to construct the integer
        // arithmetically.

        // Small wrapper to return an array
        // from a lambda.
        struct arr_wrap {
            ::mp_limb_t arr[nlimbs];
        };

        constexpr auto limb_arr = [parse_limb]() {
            arr_wrap retval{};

            // Manually compute the first limb, which might
            // contain fewer digits than the others (in which
            // case rem is non-null).
            constexpr auto rem = ndigits % nd_limb;
            const auto idx_end1 = sizeof...(Chars) - ndigits + (rem == 0u ? nd_limb : rem);
            retval.arr[0] = parse_limb(sizeof...(Chars) - ndigits, idx_end1);

            for (std::size_t i = 1; i < nlimbs; ++i) {
                retval.arr[i] = parse_limb(idx_end1 + (i - 1u) * nd_limb, idx_end1 + i * nd_limb);
            }

            return retval;
        }();

        // Turn the limb array into an integer.
        // Start with the least significant limb.
        integer<SSize> retval{limb_arr.arr[nlimbs - 1u]}, tmp;

        // A couple of variables used only in base 10.
        [[maybe_unused]] const auto factor10 = []() {
            if constexpr (base == 10) {
                return mppp::pow_ui(integer<SSize>{10}, nd_limb);
            } else {
                return 0;
            }
        }();
        [[maybe_unused]] auto cur_factor10(factor10);

        if constexpr (base != 10) {
            // NOTE: for bases other than 10, we will use bit shifting below.
            // Make sure that we can represent the max shift amount
            // via std::size_t.
            static_assert(nlimbs <= std::numeric_limits<std::size_t>::max()
                                        / static_cast<unsigned>(std::numeric_limits<::mp_limb_t>::digits));
        }

        for (std::size_t i = nlimbs - 1u; i > 0u; --i) {
            tmp = limb_arr.arr[i - 1u];

            if constexpr (base == 2) {
                tmp <<= (nd_limb * (nlimbs - i));
            } else if constexpr (base == 8) {
                tmp <<= (nd_limb * 3u * (nlimbs - i));
            } else if constexpr (base == 16) {
                tmp <<= (nd_limb * 4u * (nlimbs - i));
            } else {
                tmp *= cur_factor10;
                cur_factor10 *= factor10;
            }

            retval += tmp;
        }

        return retval;
    }
#else
    // Run the checks on the char sequence, and determine the base.
    const auto base = integer_literal_check_str(arr);
    assert(base == 2 || base == 8 || base == 10 || base == 16);

    switch (base) {
        case 2:
            return integer<SSize>{arr + 2, arr + sizeof(arr) - 1, 2};
        case 8:
            return integer<SSize>{arr + 1, arr + sizeof(arr) - 1, 8};
        case 16:
            return integer<SSize>{arr + 2, arr + sizeof(arr) - 1, 16};
        default:
            return integer<SSize>{arr};
    }
#endif
}

} // namespace detail

inline namespace literals
{

#define MPPP_DECLARE_INTEGRAL_UDL(n)                                                                                \
    template <char... Chars>                                                                                \
    inline integer<n> operator"" _z##n()                                                                               \
    {                                                                                \
        return detail::integer_literal_impl<n, Chars...>();                                                            \
    }

MPPP_DECLARE_INTEGRAL_UDL(1)
MPPP_DECLARE_INTEGRAL_UDL(2)
MPPP_DECLARE_INTEGRAL_UDL(3)

#undef MPPP_DECLARE_INTEGRAL_UDL

} // namespace literals

} // namespace mppp

#endif
<commit_msg>workaround for AppleClang<commit_after>// Copyright 2016-2020 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef MPPP_DETAIL_INTEGER_LITERALS_HPP
#define MPPP_DETAIL_INTEGER_LITERALS_HPP

#include <cassert>
#include <cstddef>
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>

#include <mp++/config.hpp>
#include <mp++/detail/gmp.hpp>
#include <mp++/detail/utils.hpp>

namespace mppp
{

namespace detail
{

// Helper to check if an integral literal is valid.
// It will return the base of the literal. Supported
// bases are 2, 8, 10 and 16.
// NOTE: we need this function in the C++11/C++14 implementation
// as well, so use MPPP_CONSTEXPR_14, MPPP_FALLTHROUGH, etc.
template <std::size_t Size>
inline
#if !defined(_MSC_VER) || defined(__clang__)
    MPPP_CONSTEXPR_14
#endif
    int
    integer_literal_check_str(const char (&arr)[Size])
{
    // We expect the size of the array to be
    // always at least 2, the null terminator
    // plus at least one char from the literal.
    static_assert(Size >= 2u, "Invalid array size.");
#if MPPP_CPLUSPLUS >= 201703L
    assert(arr[Size - 1u] == '\0');
#endif

    // The actual string length of the literal.
    constexpr auto str_length = Size - 1u;

    // Helpers to check a digit in various bases.
    auto base10_digit_check = [&arr](char c) {
        if (c < '0' || c > '9') {
            throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
        }
    };

    auto base8_digit_check = [&arr](char c) {
        if (c < '0' || c > '7') {
            throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
        }
    };

    auto base2_digit_check = [&arr](char c) {
        if (c != '0' && c != '1') {
            throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
        }
    };

    auto base16_digit_check = [&arr](char c) {
        if (c < '0' || c > '9') {
            switch (c) {
                case 'a':
                    MPPP_FALLTHROUGH;
                case 'b':
                    MPPP_FALLTHROUGH;
                case 'c':
                    MPPP_FALLTHROUGH;
                case 'd':
                    MPPP_FALLTHROUGH;
                case 'e':
                    MPPP_FALLTHROUGH;
                case 'f':
                    MPPP_FALLTHROUGH;
                case 'A':
                    MPPP_FALLTHROUGH;
                case 'B':
                    MPPP_FALLTHROUGH;
                case 'C':
                    MPPP_FALLTHROUGH;
                case 'D':
                    MPPP_FALLTHROUGH;
                case 'E':
                    MPPP_FALLTHROUGH;
                case 'F':
                    return;
                default:
                    throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
            }
        }
    };

    if (str_length == 1u) {
        // If the string length is 1, the only
        // character must be in the ['0', '9'] range.
        base10_digit_check(arr[0]);

        // NOTE: the literal "0" is actually an
        // octal, but it does not matter if we
        // construct it using base 10.
        return 10;
    }

    // The string length is at least 2. Infer the base
    // of the literal.
    const int base = [&arr, base8_digit_check, base10_digit_check]() -> int {
        // Fetch the first 2 digits.
        const auto d0 = arr[0], d1 = arr[1];

        if (d0 == '0') {
            // Binary, octal or hex.
            if (d1 == 'b' || d1 == 'B') {
                return 2;
            } else if (d1 == 'x' || d1 == 'X') {
                return 16;
            } else {
                base8_digit_check(d1);
                return 8;
            }
        } else {
            // Decimal.
            base10_digit_check(d0);
            base10_digit_check(d1);
            return 10;
        }
    }();

#if MPPP_CPLUSPLUS >= 201703L
    assert(base == 2 || base == 8 || base == 10 || base == 16);
#endif

    // Run the checks on the rest of the literal,
    // after we already checked the first 2 digits.
    // For bases 2 and 16, we need to have other digits,
    // otherwise the literal is malformed.
    // NOLINTNEXTLINE(hicpp-multiway-paths-covered)
    switch (base) {
        case 2:
            if (str_length == 2u) {
                throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
            }
            for (std::size_t i = 2; i < str_length; ++i) {
                base2_digit_check(arr[i]);
            }
            break;
        case 8:
            for (std::size_t i = 2; i < str_length; ++i) {
                base8_digit_check(arr[i]);
            }
            break;
        case 10:
            for (std::size_t i = 2; i < str_length; ++i) {
                base10_digit_check(arr[i]);
            }
            break;
        case 16:
            if (str_length == 2u) {
                throw std::invalid_argument("Invalid integral literal: " + std::string(arr));
            }
            for (std::size_t i = 2; i < str_length; ++i) {
                base16_digit_check(arr[i]);
            }
    }

    return base;
}

#if MPPP_CPLUSPLUS >= 201703L && (!defined(_MSC_VER) || defined(__clang__))

// Small helper to convert the char representation
// of a digit into the corresponding numerical
// value for a given Base. Base must be one
// of 2, 8, 10 or 16, and Int must be some integral
// type.
template <int Base, typename Int>
constexpr Int digit_to_value(char c)
{
    static_assert(std::is_integral_v<Int>);
    static_assert(Base == 2 || Base == 8 || Base == 10 || Base == 16);

    if constexpr (Base == 16) {
        if (c >= '0' && c <= '9') {
            return static_cast<Int>(c - '0');
        } else {
            switch (c) {
                case 'a':
                    [[fallthrough]];
                case 'A':
                    return static_cast<Int>(10);
                case 'b':
                    [[fallthrough]];
                case 'B':
                    return static_cast<Int>(11);
                case 'c':
                    [[fallthrough]];
                case 'C':
                    return static_cast<Int>(12);
                case 'd':
                    [[fallthrough]];
                case 'D':
                    return static_cast<Int>(13);
                case 'e':
                    [[fallthrough]];
                case 'E':
                    return static_cast<Int>(14);
                default:
                    assert(c == 'f' || c == 'F');
                    return static_cast<Int>(15);
            }
        }
    } else {
        if constexpr (Base == 2) {
            assert(c == '0' || c == '1');
        } else if constexpr (Base == 8) {
            assert(c >= '0' && c <= '7');
        } else {
            assert(c >= '0' && c <= '9');
        }
        return static_cast<Int>(c - '0');
    }
}

#endif

template <std::size_t SSize, char... Chars>
inline integer<SSize> integer_literal_impl()
{
    // Turn the sequence of input chars
    // into a null-terminated char array.
    // NOTE: earlier clang versions won't properly
    // capture arr in the lambdas below if it is
    // not marked as static.
#if defined(__clang__) && (defined(__apple_build_version__) || __clang_major__ <= 5)
    static
#endif
        constexpr char arr[]
        = {Chars..., '\0'};

#if MPPP_CPLUSPLUS >= 201703L && (!defined(_MSC_VER) || defined(__clang__)) && !defined(__INTEL_COMPILER)
    // Run the checks on the char sequence, and determine the base.
    constexpr auto base = integer_literal_check_str(arr);
    static_assert(base == 2 || base == 8 || base == 10 || base == 16);

    // The actual number of digits in the literal
    // (discounting prefixes).
    constexpr auto ndigits = (base == 2 || base == 16) ? (sizeof...(Chars) - 2u)
                                                       : (base == 8 ? (sizeof...(Chars) - 1u) : sizeof...(Chars));

    // Determine how many digits in the given base we can always fit
    // into a single mp_limb_t.
    constexpr auto nd_limb = static_cast<unsigned>([]() {
        [[maybe_unused]] constexpr auto nbits = std::numeric_limits<::mp_limb_t>::digits;

        if constexpr (base == 2) {
            // Base 2, just return the number of bits.
            return nbits;
        } else if constexpr (base == 8) {
            // Base 8, need 3 bits per digit.
            return nbits / 3;
        } else if constexpr (base == 16) {
            // Base 16, need 4 bits per digit.
            return nbits / 4;
        } else {
            // Base 10, use digits10.
            return std::numeric_limits<::mp_limb_t>::digits10;
        }
    }());

    // Determine how many instances of mp_limb_t we need
    // to represent the literal.
    constexpr auto nlimbs = ndigits / nd_limb + static_cast<unsigned>(ndigits % nd_limb != 0u);
    static_assert(nlimbs > 0u);

    // Helper function to parse a single limb from a subset
    // of digits at indices [begin, end) in the literal.
    auto parse_limb = [](std::size_t begin, std::size_t end) {
        ::mp_limb_t retval = 0, shifter = 1;

        for (auto i = end; i > begin; --i) {
            const auto cur_digit = digit_to_value<base, ::mp_limb_t>(arr[i - 1u]);
            retval += cur_digit * shifter;

            if (i > begin + 1u) {
                // If this is not the last iteration, update the shifter.
                shifter *= static_cast<::mp_limb_t>(base);
            }
        }

        return retval;
    };

    if constexpr (nlimbs == 1u) {
        // Fast path if the literal fits into
        // a single mp_limb_t.
        constexpr auto l = parse_limb(sizeof...(Chars) - ndigits, sizeof...(Chars));

        return integer<SSize>{l};
    } else {
        // The literal needs more than 1 limb:
        // build an array of limbs from the literal
        // and use it to construct the integer
        // arithmetically.

        // Small wrapper to return an array
        // from a lambda.
        struct arr_wrap {
            ::mp_limb_t arr[nlimbs];
        };

        constexpr auto limb_arr = [parse_limb]() {
            arr_wrap retval{};

            // Manually compute the first limb, which might
            // contain fewer digits than the others (in which
            // case rem is non-null).
            constexpr auto rem = ndigits % nd_limb;
            const auto idx_end1 = sizeof...(Chars) - ndigits + (rem == 0u ? nd_limb : rem);
            retval.arr[0] = parse_limb(sizeof...(Chars) - ndigits, idx_end1);

            for (std::size_t i = 1; i < nlimbs; ++i) {
                retval.arr[i] = parse_limb(idx_end1 + (i - 1u) * nd_limb, idx_end1 + i * nd_limb);
            }

            return retval;
        }();

        // Turn the limb array into an integer.
        // Start with the least significant limb.
        integer<SSize> retval{limb_arr.arr[nlimbs - 1u]}, tmp;

        // A couple of variables used only in base 10.
        [[maybe_unused]] const auto factor10 = []() {
            if constexpr (base == 10) {
                return mppp::pow_ui(integer<SSize>{10}, nd_limb);
            } else {
                return 0;
            }
        }();
        [[maybe_unused]] auto cur_factor10(factor10);

        if constexpr (base != 10) {
            // NOTE: for bases other than 10, we will use bit shifting below.
            // Make sure that we can represent the max shift amount
            // via std::size_t.
            static_assert(nlimbs <= std::numeric_limits<std::size_t>::max()
                                        / static_cast<unsigned>(std::numeric_limits<::mp_limb_t>::digits));
        }

        for (std::size_t i = nlimbs - 1u; i > 0u; --i) {
            tmp = limb_arr.arr[i - 1u];

            if constexpr (base == 2) {
                tmp <<= (nd_limb * (nlimbs - i));
            } else if constexpr (base == 8) {
                tmp <<= (nd_limb * 3u * (nlimbs - i));
            } else if constexpr (base == 16) {
                tmp <<= (nd_limb * 4u * (nlimbs - i));
            } else {
                tmp *= cur_factor10;
                cur_factor10 *= factor10;
            }

            retval += tmp;
        }

        return retval;
    }
#else
    // Run the checks on the char sequence, and determine the base.
    const auto base = integer_literal_check_str(arr);
    assert(base == 2 || base == 8 || base == 10 || base == 16);

    switch (base) {
        case 2:
            return integer<SSize>{arr + 2, arr + sizeof(arr) - 1, 2};
        case 8:
            return integer<SSize>{arr + 1, arr + sizeof(arr) - 1, 8};
        case 16:
            return integer<SSize>{arr + 2, arr + sizeof(arr) - 1, 16};
        default:
            return integer<SSize>{arr};
    }
#endif
}

} // namespace detail

inline namespace literals
{

#define MPPP_DECLARE_INTEGRAL_UDL(n)                                                                                \
    template <char... Chars>                                                                                \
    inline integer<n> operator"" _z##n()                                                                               \
    {                                                                                \
        return detail::integer_literal_impl<n, Chars...>();                                                            \
    }

MPPP_DECLARE_INTEGRAL_UDL(1)
MPPP_DECLARE_INTEGRAL_UDL(2)
MPPP_DECLARE_INTEGRAL_UDL(3)

#undef MPPP_DECLARE_INTEGRAL_UDL

} // namespace literals

} // namespace mppp

#endif
<|endoftext|>


<commit_before>#include "dram_directory_cache.h"
#include "log.h"
#include "utils.h"

namespace PrL1PrL2DramDirectoryMSI
{

DramDirectoryCache::DramDirectoryCache(
      std::string directory_type_str,
      UInt32 total_entries,
      UInt32 associativity,
      UInt32 cache_block_size,
      UInt32 max_hw_sharers,
      UInt32 max_num_sharers,
      UInt32 dram_directory_cache_access_time,
      ShmemPerfModel* shmem_perf_model):
   m_total_entries(total_entries),
   m_associativity(associativity),
   m_cache_block_size(cache_block_size),
   m_dram_directory_cache_access_time(dram_directory_cache_access_time),
   m_shmem_perf_model(shmem_perf_model)
{
   m_num_sets = m_total_entries / m_associativity;

   // Instantiate the directory
   m_directory = new Directory(directory_type_str, total_entries, max_hw_sharers, max_num_sharers);

   // Logs
   m_log_num_sets = floorLog2(m_num_sets);
   m_log_cache_block_size = floorLog2(m_cache_block_size);
}

DramDirectoryCache::~DramDirectoryCache()
{
   delete m_directory;
}

DirectoryEntry*
DramDirectoryCache::getDirectoryEntry(IntPtr address)
{
   if (m_shmem_perf_model)
      getShmemPerfModel()->incrCycleCount(m_dram_directory_cache_access_time);

   IntPtr tag;
   UInt32 set_index;

   // Assume that it always hit in the Dram Directory Cache for now
   splitAddress(address, tag, set_index);

   // Find the relevant directory entry
   for (UInt32 i = 0; i < m_associativity; i++)
   {
      DirectoryEntry* directory_entry = m_directory->getDirectoryEntry(set_index * m_associativity + i);
      if (m_shmem_perf_model)
         getShmemPerfModel()->incrCycleCount(directory_entry->getLatency());

      if (directory_entry->getAddress() == address)
      {
         // Simple check for now. Make sophisticated later
         return directory_entry;
      }
   }

   // Find a free directory entry if one does not currently exist
   for (UInt32 i = 0; i < m_associativity; i++)
   {
      DirectoryEntry* directory_entry = m_directory->getDirectoryEntry(set_index * m_associativity + i);
      if (directory_entry->getAddress() == INVALID_ADDRESS)
      {
         // Simple check for now. Make sophisticated later
         directory_entry->setAddress(address);
         return directory_entry;
      }
   }

   // Check in the m_replaced_directory_entry_list
   std::vector<DirectoryEntry*>::iterator it;
   for (it = m_replaced_directory_entry_list.begin(); it != m_replaced_directory_entry_list.end(); it++)
   {
      if ((*it)->getAddress() == address)
      {
         return (*it);
      }
   }

   return (DirectoryEntry*) NULL;
}

void
DramDirectoryCache::getReplacementCandidates(IntPtr address, std::vector<DirectoryEntry*>& replacement_candidate_list)
{
   assert(getDirectoryEntry(address) == NULL);

   IntPtr tag;
   UInt32 set_index;
   splitAddress(address, tag, set_index);

   for (UInt32 i = 0; i < m_associativity; i++)
   {
      replacement_candidate_list.push_back(m_directory->getDirectoryEntry(set_index * m_associativity + i));
   }
}

DirectoryEntry*
DramDirectoryCache::replaceDirectoryEntry(IntPtr replaced_address, IntPtr address)
{
   IntPtr tag;
   UInt32 set_index;
   splitAddress(replaced_address, tag, set_index);

   for (UInt32 i = 0; i < m_associativity; i++)
   {
      DirectoryEntry* replaced_directory_entry = m_directory->getDirectoryEntry(set_index * m_associativity + i);
      if (replaced_directory_entry->getAddress() == replaced_address)
      {
         m_replaced_directory_entry_list.push_back(replaced_directory_entry);

         DirectoryEntry* directory_entry = m_directory->createDirectoryEntry();
         directory_entry->setAddress(address);
         m_directory->setDirectoryEntry(set_index * m_associativity + i, directory_entry);

         return directory_entry;
      }
   }

   // Should not reach here
   assert(false);
}

void
DramDirectoryCache::invalidateDirectoryEntry(IntPtr address)
{
   std::vector<DirectoryEntry*>::iterator it;
   for (it = m_replaced_directory_entry_list.begin(); it != m_replaced_directory_entry_list.end(); it++)
   {
      if ((*it)->getAddress() == address)
      {
         delete (*it);
         m_replaced_directory_entry_list.erase(it);

         return;
      }
   }

   // Should not reach here
   assert(false);
}

void
DramDirectoryCache::splitAddress(IntPtr address, IntPtr& tag, UInt32& set_index)
{
   IntPtr cache_block_address = address >> getLogCacheBlockSize();
   tag = cache_block_address >> getLogNumSets();
   set_index = ((UInt32) cache_block_address) & (getNumSets() - 1);

}

}
<commit_msg>[shared mem] Small change to a performance model<commit_after>#include "dram_directory_cache.h"
#include "log.h"
#include "utils.h"

namespace PrL1PrL2DramDirectoryMSI
{

DramDirectoryCache::DramDirectoryCache(
      std::string directory_type_str,
      UInt32 total_entries,
      UInt32 associativity,
      UInt32 cache_block_size,
      UInt32 max_hw_sharers,
      UInt32 max_num_sharers,
      UInt32 dram_directory_cache_access_time,
      ShmemPerfModel* shmem_perf_model):
   m_total_entries(total_entries),
   m_associativity(associativity),
   m_cache_block_size(cache_block_size),
   m_dram_directory_cache_access_time(dram_directory_cache_access_time),
   m_shmem_perf_model(shmem_perf_model)
{
   m_num_sets = m_total_entries / m_associativity;

   // Instantiate the directory
   m_directory = new Directory(directory_type_str, total_entries, max_hw_sharers, max_num_sharers);

   // Logs
   m_log_num_sets = floorLog2(m_num_sets);
   m_log_cache_block_size = floorLog2(m_cache_block_size);
}

DramDirectoryCache::~DramDirectoryCache()
{
   delete m_directory;
}

DirectoryEntry*
DramDirectoryCache::getDirectoryEntry(IntPtr address)
{
   if (m_shmem_perf_model)
      getShmemPerfModel()->incrCycleCount(m_dram_directory_cache_access_time);

   IntPtr tag;
   UInt32 set_index;

   // Assume that it always hit in the Dram Directory Cache for now
   splitAddress(address, tag, set_index);

   // Find the relevant directory entry
   for (UInt32 i = 0; i < m_associativity; i++)
   {
      DirectoryEntry* directory_entry = m_directory->getDirectoryEntry(set_index * m_associativity + i);

      if (directory_entry->getAddress() == address)
      {
         if (m_shmem_perf_model)
            getShmemPerfModel()->incrCycleCount(directory_entry->getLatency());
         // Simple check for now. Make sophisticated later
         return directory_entry;
      }
   }

   // Find a free directory entry if one does not currently exist
   for (UInt32 i = 0; i < m_associativity; i++)
   {
      DirectoryEntry* directory_entry = m_directory->getDirectoryEntry(set_index * m_associativity + i);
      if (directory_entry->getAddress() == INVALID_ADDRESS)
      {
         // Simple check for now. Make sophisticated later
         directory_entry->setAddress(address);
         return directory_entry;
      }
   }

   // Check in the m_replaced_directory_entry_list
   std::vector<DirectoryEntry*>::iterator it;
   for (it = m_replaced_directory_entry_list.begin(); it != m_replaced_directory_entry_list.end(); it++)
   {
      if ((*it)->getAddress() == address)
      {
         return (*it);
      }
   }

   return (DirectoryEntry*) NULL;
}

void
DramDirectoryCache::getReplacementCandidates(IntPtr address, std::vector<DirectoryEntry*>& replacement_candidate_list)
{
   assert(getDirectoryEntry(address) == NULL);

   IntPtr tag;
   UInt32 set_index;
   splitAddress(address, tag, set_index);

   for (UInt32 i = 0; i < m_associativity; i++)
   {
      replacement_candidate_list.push_back(m_directory->getDirectoryEntry(set_index * m_associativity + i));
   }
}

DirectoryEntry*
DramDirectoryCache::replaceDirectoryEntry(IntPtr replaced_address, IntPtr address)
{
   if (m_shmem_perf_model)
      getShmemPerfModel()->incrCycleCount(m_dram_directory_cache_access_time);

   IntPtr tag;
   UInt32 set_index;
   splitAddress(replaced_address, tag, set_index);

   for (UInt32 i = 0; i < m_associativity; i++)
   {
      DirectoryEntry* replaced_directory_entry = m_directory->getDirectoryEntry(set_index * m_associativity + i);
      if (replaced_directory_entry->getAddress() == replaced_address)
      {
         m_replaced_directory_entry_list.push_back(replaced_directory_entry);

         DirectoryEntry* directory_entry = m_directory->createDirectoryEntry();
         directory_entry->setAddress(address);
         m_directory->setDirectoryEntry(set_index * m_associativity + i, directory_entry);

         return directory_entry;
      }
   }

   // Should not reach here
   assert(false);
}

void
DramDirectoryCache::invalidateDirectoryEntry(IntPtr address)
{
   std::vector<DirectoryEntry*>::iterator it;
   for (it = m_replaced_directory_entry_list.begin(); it != m_replaced_directory_entry_list.end(); it++)
   {
      if ((*it)->getAddress() == address)
      {
         delete (*it);
         m_replaced_directory_entry_list.erase(it);

         return;
      }
   }

   // Should not reach here
   assert(false);
}

void
DramDirectoryCache::splitAddress(IntPtr address, IntPtr& tag, UInt32& set_index)
{
   IntPtr cache_block_address = address >> getLogCacheBlockSize();
   tag = cache_block_address >> getLogNumSets();
   set_index = ((UInt32) cache_block_address) & (getNumSets() - 1);

}

}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit (ITK)
  Module:    itkBasicArchitectureTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2000 National Library of Medicine
All rights reserved.

See COPYRIGHT.txt for copyright details.

=========================================================================*/
#include <iostream>
#include "itkImage.h"
#include "itkScalar.h"
#include "itkVector.h"
#include "itkRandomImageSource.h"
#include "itkShrinkImage.h"
#include "itkWriteVTKImage.h"
#include "itkReadVTKImage.h"
#include "itkCommand.h"
#include "itkOutputWindow.h"

// this class is used to send output to stdout and not the itk window
class TextOutput : public itk::OutputWindow
{
public:
  virtual void DisplayText(const char* s)
    {
      std::cout << s << std::endl;
    }
};

// The following three classes are used to support callbacks
// on the shrink filter in the pipeline that follows later
class ShowProgressObject
{
public:
  ShowProgressObject(itk::ProcessObject* o)
    {m_Process = o;}
  void ShowProgress()
    {std::cout << "Progress " << m_Process->GetProgress() << std::endl;}
  itk::ProcessObject::Pointer m_Process;
};

class StartEndEvent
{
public:
  void Start()
    {std::cout << "start event" << std::endl;}
  void End()
    {std::cout << "end event " << std::endl;}
};

class AllEvents
{
public:
  void WatchEvents(itk::LightObject *caller, unsigned long event)
    {
      const char* eventName = 0;
      switch(event)
        {
        case itk::Command::DeleteEvent:
          eventName = "DeleteEvent";
          break;
        case itk::Command::StartEvent:
          eventName = "StartEvent";
          break;
        case itk::Command::EndEvent:
          eventName = "EndEvent";
          break;
        case itk::Command::ProgressEvent:
          {
          itk::ProcessObject* obj = dynamic_cast<itk::ProcessObject*>(caller);
          std::cout << "AnyEvent Progress " << obj->GetProgress() << std::endl;
          eventName = "ProgressEvent";
          break;
          }
        case itk::Command::PickEvent:
          eventName = "PickEvent";
          break;
        case itk::Command::StartPickEvent:
          eventName = "StartPickEvent";
          break;
        case itk::Command::AbortCheckEvent:
          eventName = "AbortCheckEvent";
          break;
        case itk::Command::ExitEvent:
          eventName = "ExitEvent";
          break;
        default:
          eventName = "UserEvent";
        }
      std::cout << "Event name: " << eventName << " Id: " << event << std::endl;
    }
};

int main()
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(new TextOutput);
  // Uncomment the following if you want to see each message independently
  // itk::OutputWindow::GetInstance()->PromptUserOn();

  // Test the creation of an image with native type
  //
  itk::Image<float,2>::Pointer if2 = itk::Image<float,2>::New();

  std::cout << std::endl
            << "Image dimension is " << itk::Image<float,5>::ImageDimension
            << std::endl;
  std::cout << "Image dimension is " << itk::Image<short,1>::ImageDimension
            << std::endl;

  // Begin by creating a simple pipeline. Use the Scalar class as a pixel.
  //
  // Create a typedef to make the code more digestable
  typedef itk::Image<itk::Scalar<float>,2> FloatImage2DType;

  // Create a source object (in this case a reader)
  itk::ReadVTKImage<FloatImage2DType>::Pointer reader;
  reader = itk::ReadVTKImage<FloatImage2DType>::New();
  reader->SetFileName("junkInput.vtk");

  // Create another source object (in this case a random image generator).
  // The source object is templated on the output type.
  //
  itk::RandomImageSource<FloatImage2DType>::Pointer random;
  random = itk::RandomImageSource<FloatImage2DType>::New();
  random->SetMin(0.0);
  random->SetMax(1.0);

  // Create a filter...shrink the image by an integral amount. We also
  // add some callbacks to the start, progress, and end filter execution
  // methods. The filter is templated on the input and output data types.
  //
  itk::ShrinkImage<FloatImage2DType,FloatImage2DType>::Pointer shrink;
  shrink = itk::ShrinkImage<FloatImage2DType,FloatImage2DType>::New();
  shrink->SetInput(random->GetOutput());
  shrink->SetShrinkFactor(2);
  shrink->DebugOn();

  // Create a command to call ShowProgress when progress event is triggered
  ShowProgressObject progressWatch(shrink);
  itk::SimpleMemberCommand<ShowProgressObject>::Pointer command;
  command = itk::SimpleMemberCommand<ShowProgressObject>::New();
  command->SetCallbackFunction(&progressWatch,
                               ShowProgressObject::ShowProgress);
  shrink->AddObserver(itk::Command::ProgressEvent, command);

  // Create a command to call StartEndEvent when start event is triggered
  StartEndEvent startEndWatch;
  itk::SimpleMemberCommand<StartEndEvent>::Pointer start;
  start = itk::SimpleMemberCommand<StartEndEvent>::New();
  start->SetCallbackFunction(&startEndWatch, StartEndEvent::Start);
  shrink->AddObserver(itk::Command::StartEvent, start);

  // Create a command to call StartEndEvent when end event is triggered
  itk::SimpleMemberCommand<StartEndEvent>::Pointer end;
  end = itk::SimpleMemberCommand<StartEndEvent>::New();
  end->SetCallbackFunction(&startEndWatch, StartEndEvent::End);
  shrink->AddObserver(itk::Command::EndEvent, end);

  // Create a command that to call AnyEvent when event is fired
  AllEvents allWatch;
  itk::MemberCommand<AllEvents>::Pointer allEvents;
  allEvents = itk::MemberCommand<AllEvents>::New();
  allEvents->SetCallbackFunction(&allWatch,
                                 AllEvents::WatchEvents);
  shrink->AddObserver(itk::Command::AnyEvent, allEvents);

  // Create a mapper (in this case a writer). A mapper
  // is templated on the input type.
  //
  itk::WriteVTKImage<FloatImage2DType>::Pointer writer;
  writer = itk::WriteVTKImage<FloatImage2DType>::New();
  writer->SetInput(shrink->GetOutput());
  writer->SetFileName("junkImage.vtk");
  writer->SetFileTypeToASCII();
  writer->DebugOn();
  writer->Write();

  return EXIT_SUCCESS;
}

<commit_msg>ENH:Added test for RawImageWriter<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit (ITK)
  Module:    itkBasicArchitectureTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2000 National Library of Medicine
All rights reserved.

See COPYRIGHT.txt for copyright details.

=========================================================================*/
#include <iostream>
#include "itkImage.h"
#include "itkScalar.h"
#include "itkVector.h"
#include "itkRandomImageSource.h"
#include "itkShrinkImage.h"
#include "itkWriteVTKImage.h"
#include "itkWriteRawImage.h"
#include "itkReadVTKImage.h"
#include "itkCommand.h"
#include "itkOutputWindow.h"

// this class is used to send output to stdout and not the itk window
class TextOutput : public itk::OutputWindow
{
public:
  virtual void DisplayText(const char* s)
    {
      std::cout << s << std::endl;
    }
};

// The following three classes are used to support callbacks
// on the shrink filter in the pipeline that follows later
class ShowProgressObject
{
public:
  ShowProgressObject(itk::ProcessObject* o)
    {m_Process = o;}
  void ShowProgress()
    {std::cout << "Progress " << m_Process->GetProgress() << std::endl;}
  itk::ProcessObject::Pointer m_Process;
};

class StartEndEvent
{
public:
  void Start()
    {std::cout << "start event" << std::endl;}
  void End()
    {std::cout << "end event " << std::endl;}
};

class AllEvents
{
public:
  void WatchEvents(itk::LightObject *caller, unsigned long event)
    {
      const char* eventName = 0;
      switch(event)
        {
        case itk::Command::DeleteEvent:
          eventName = "DeleteEvent";
          break;
        case itk::Command::StartEvent:
          eventName = "StartEvent";
          break;
        case itk::Command::EndEvent:
          eventName = "EndEvent";
          break;
        case itk::Command::ProgressEvent:
          {
          itk::ProcessObject* obj = dynamic_cast<itk::ProcessObject*>(caller);
          std::cout << "AnyEvent Progress " << obj->GetProgress() << std::endl;
          eventName = "ProgressEvent";
          break;
          }
        case itk::Command::PickEvent:
          eventName = "PickEvent";
          break;
        case itk::Command::StartPickEvent:
          eventName = "StartPickEvent";
          break;
        case itk::Command::AbortCheckEvent:
          eventName = "AbortCheckEvent";
          break;
        case itk::Command::ExitEvent:
          eventName = "ExitEvent";
          break;
        default:
          eventName = "UserEvent";
        }
      std::cout << "Event name: " << eventName << " Id: " << event << std::endl;
    }
};

int main()
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(new TextOutput);
  // Uncomment the following if you want to see each message independently
  // itk::OutputWindow::GetInstance()->PromptUserOn();

  // Test the creation of an image with native type
  //
  itk::Image<float,2>::Pointer if2 = itk::Image<float,2>::New();

  std::cout << std::endl
            << "Image dimension is " << itk::Image<float,5>::ImageDimension
            << std::endl;
  std::cout << "Image dimension is " << itk::Image<short,1>::ImageDimension
            << std::endl;

  // Begin by creating a simple pipeline. Use the Scalar class as a pixel.
  //
  // Create a typedef to make the code more digestable
  typedef itk::Image<itk::Scalar<float>,2> FloatImage2DType;

  // Create a source object (in this case a reader)
  itk::ReadVTKImage<FloatImage2DType>::Pointer reader;
  reader = itk::ReadVTKImage<FloatImage2DType>::New();
  reader->SetFileName("junkInput.vtk");

  // Create another source object (in this case a random image generator).
  // The source object is templated on the output type.
  //
  itk::RandomImageSource<FloatImage2DType>::Pointer random;
  random = itk::RandomImageSource<FloatImage2DType>::New();
  random->SetMin(0.0);
  random->SetMax(1.0);

  // Create a filter...shrink the image by an integral amount. We also
  // add some callbacks to the start, progress, and end filter execution
  // methods. The filter is templated on the input and output data types.
  //
  itk::ShrinkImage<FloatImage2DType,FloatImage2DType>::Pointer shrink;
  shrink = itk::ShrinkImage<FloatImage2DType,FloatImage2DType>::New();
  shrink->SetInput(random->GetOutput());
  shrink->SetShrinkFactor(2);
  shrink->DebugOn();

  // Create a command to call ShowProgress when progress event is triggered
  ShowProgressObject progressWatch(shrink);
  itk::SimpleMemberCommand<ShowProgressObject>::Pointer command;
  command = itk::SimpleMemberCommand<ShowProgressObject>::New();
  command->SetCallbackFunction(&progressWatch,
                               ShowProgressObject::ShowProgress);
  shrink->AddObserver(itk::Command::ProgressEvent, command);

  // Create a command to call StartEndEvent when start event is triggered
  StartEndEvent startEndWatch;
  itk::SimpleMemberCommand<StartEndEvent>::Pointer start;
  start = itk::SimpleMemberCommand<StartEndEvent>::New();
  start->SetCallbackFunction(&startEndWatch, StartEndEvent::Start);
  shrink->AddObserver(itk::Command::StartEvent, start);

  // Create a command to call StartEndEvent when end event is triggered
  itk::SimpleMemberCommand<StartEndEvent>::Pointer end;
  end = itk::SimpleMemberCommand<StartEndEvent>::New();
  end->SetCallbackFunction(&startEndWatch, StartEndEvent::End);
  shrink->AddObserver(itk::Command::EndEvent, end);

  // Create a command that to call AnyEvent when event is fired
  AllEvents allWatch;
  itk::MemberCommand<AllEvents>::Pointer allEvents;
  allEvents = itk::MemberCommand<AllEvents>::New();
  allEvents->SetCallbackFunction(&allWatch,
                                 AllEvents::WatchEvents);
  shrink->AddObserver(itk::Command::AnyEvent, allEvents);

  // Create a mapper (in this case a writer). A mapper
  // is templated on the input type.
  //
  itk::WriteVTKImage<FloatImage2DType>::Pointer writer;
  writer = itk::WriteVTKImage<FloatImage2DType>::New();
  writer->SetInput(shrink->GetOutput());
  writer->SetFileName("BasicArchitectureImage.vtk");
  writer->SetFileTypeToASCII();
  writer->DebugOn();
  writer->Write();

  itk::WriteRawImage<FloatImage2DType>::Pointer rawWriter;
  rawWriter = itk::WriteRawImage<FloatImage2DType>::New();
  rawWriter->SetInput(shrink->GetOutput());
  rawWriter->SetFileName("BasicArchitectureImage.dat");
  rawWriter->SetFileTypeToBinary();
  rawWriter->SetByteOrderToBigEndian();
  rawWriter->DebugOn();
  rawWriter->Write();

  return EXIT_SUCCESS;
}

<|endoftext|>