<commit_before>/*  This file is part of the Tufão project
    Copyright (C) 2011 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>

    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, see <http://www.gnu.org/licenses/>.
*/

#include "reasonphrase.h"
#include <QtCore/QMap>
#include <QtCore/QByteArray>

namespace Tufao {

struct Phrases
{
    Phrases();

    QMap<int, QByteArray> map;
};

inline Phrases::Phrases()
{
    // 1xx Informational
    map[100] = "Continue";
    map[101] = "Switching Protocols";
    map[102] = "Processing";
    map[103] = "Checkpoint";

    // 2xx Successful
    map[200] = "OK";
    map[201] = "Created";
    map[202] = "Accepted";
    map[203] = "Non-Authoritative Information";
    map[204] = "No Content";
    map[205] = "Reset Content";
    map[206] = "Partial Content";
    map[207] = "Multi-Status";
    map[208] = "Already Reported";
    map[226] = "IM Used";

    // 3xx Redirection
    map[300] = "Multiple Choices";
    map[301] = "Moved Permanently";
    map[302] = "Found";
    map[303] = "See Other";
    map[304] = "Not Modified";
    map[305] = "Use Proxy";
    map[306] = "Switch Proxy";
    map[307] = "Temporary Redirect";
    map[308] = "Resume Incomplete";

    // 4xx Client Error
    map[400] = "Bad Request";
    map[401] = "Unauthorized";
    map[402] = "Payment Required";
    map[403] = "Forbidden";
    map[404] = "Not Found";
    map[405] = "Method Not Allowed";
    map[406] = "Not Acceptable";
    map[407] = "Proxy Authentication Required";
    map[408] = "Request Timeout";
    map[409] = "Conflict";
    map[410] = "Gone";
    map[411] = "Length Required";
    map[412] = "Precondition Failed";
    map[413] = "Request Entity Too Large";
    map[414] = "Request-URI Too Long";
    map[415] = "Unsupported Media Type";
    map[416] = "Requested Range Not Satisfiable";
    map[417] = "Expectation Failed";
    map[418] = "I'm a teapot";
    map[422] = "Unprocessable Entity";
    map[423] = "Locked";
    map[424] = "Failed Dependency";
    map[425] = "Unordered Collection";
    map[426] = "Upgrade Required";
    map[428] = "Precondition Required";
    map[429] = "Too Many Requests";
    map[431] = "Request Header Fields Too Large";
    map[444] = "No Response";
    map[449] = "Retry With";
    map[499] = "Client Closed Request";

    // 5xx Internal Server Error
    map[500] = "Internal Server Error";
    map[501] = "Not Implemented";
    map[502] = "Bad Gateway";
    map[503] = "Service Unavailable";
    map[504] = "Gateway Timeout";
    map[505] = "HTTP Version Not Supported";
    map[506] = "Variant Also Negotiates";
    map[507] = "Insufficient Storage";
    map[508] = "Loop Detected";
    map[509] = "Bandwidth Limit Exceeded";
    map[510] = "Not Extended";
}

static Phrases phrases;

QByteArray reasonPhrase(HttpResponseStatusCode statusCode)
{
    if (!phrases.map.contains(int(statusCode)))
        return QByteArray();

    return phrases.map[int(statusCode)];
}

} // namespace Tufao
<commit_msg>Code cleanup (initializing complex object)<commit_after>/*  This file is part of the Tufão project
    Copyright (C) 2011 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>

    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, see <http://www.gnu.org/licenses/>.
*/

#include "reasonphrase.h"
#include <QtCore/QByteArray>
#include <map>

namespace Tufao {

std::map<HttpResponseStatusCode, QByteArray> phrases {
    // 1xx Informational
    {HttpResponseStatusCode::CONTINUE, "Continue"},
    {HttpResponseStatusCode::SWITCHING_PROTOCOLS, "Switching Protocols"},
    {HttpResponseStatusCode::PROCESSING, "Processing"},
    {HttpResponseStatusCode::CHECKPOINT, "Checkpoint"},

    // 2xx Successful
    {HttpResponseStatusCode::OK, "OK"},
    {HttpResponseStatusCode::CREATED, "Created"},
    {HttpResponseStatusCode::ACCEPTED, "Accepted"},
    {HttpResponseStatusCode::NON_AUTHORITATIVE_INFORMATION,
                "Non-Authoritative Information"},
    {HttpResponseStatusCode::NO_CONTENT, "No Content"},
    {HttpResponseStatusCode::RESET_CONTENT, "Reset Content"},
    {HttpResponseStatusCode::PARTIAL_CONTENT, "Partial Content"},
    {HttpResponseStatusCode::MULTI_STATUS, "Multi-Status"},
    {HttpResponseStatusCode::ALREADY_REPORTED, "Already Reported"},
    {HttpResponseStatusCode::IM_USED, "IM Used"},

    // 3xx Redirection
    {HttpResponseStatusCode::MULTIPLE_CHOICES, "Multiple Choices"},
    {HttpResponseStatusCode::MOVED_PERMANENTLY, "Moved Permanently"},
    {HttpResponseStatusCode::FOUND, "Found"},
    {HttpResponseStatusCode::SEE_OTHER, "See Other"},
    {HttpResponseStatusCode::NOT_MODIFIED, "Not Modified"},
    {HttpResponseStatusCode::USE_PROXY, "Use Proxy"},
    {HttpResponseStatusCode::SWITCH_PROXY, "Switch Proxy"},
    {HttpResponseStatusCode::TEMPORARY_REDIRECT, "Temporary Redirect"},
    {HttpResponseStatusCode::RESUME_INCOMPLETE, "Resume Incomplete"},

    // 4xx Client Error
    {HttpResponseStatusCode::BAD_REQUEST, "Bad Request"},
    {HttpResponseStatusCode::UNAUTHORIZED, "Unauthorized"},
    {HttpResponseStatusCode::PAYMENT_REQUIRED, "Payment Required"},
    {HttpResponseStatusCode::FORBIDDEN, "Forbidden"},
    {HttpResponseStatusCode::NOT_FOUND, "Not Found"},
    {HttpResponseStatusCode::METHOD_NOT_ALLOWED, "Method Not Allowed"},
    {HttpResponseStatusCode::NOT_ACCEPTABLE, "Not Acceptable"},
    {HttpResponseStatusCode::PROXY_AUTHENTICATION_REQUIRED,
                "Proxy Authentication Required"},
    {HttpResponseStatusCode::REQUEST_TIMEOUT, "Request Timeout"},
    {HttpResponseStatusCode::CONFLICT, "Conflict"},
    {HttpResponseStatusCode::GONE, "Gone"},
    {HttpResponseStatusCode::LENGTH_REQUIRED, "Length Required"},
    {HttpResponseStatusCode::PRECONDITION_FAILED, "Precondition Failed"},
    {HttpResponseStatusCode::REQUEST_ENTITY_TOO_LARGE,
                "Request Entity Too Large"},
    {HttpResponseStatusCode::REQUEST_URI_TOO_LONG, "Request-URI Too Long"},
    {HttpResponseStatusCode::UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"},
    {HttpResponseStatusCode::REQUESTED_RANGE_NOT_SATISFIABLE,
                "Requested Range Not Satisfiable"},
    {HttpResponseStatusCode::EXPECTATION_FAILED, "Expectation Failed"},
    {HttpResponseStatusCode::I_AM_A_TEAPOT, "I'm a teapot"},
    {HttpResponseStatusCode::UNPROCESSABLE_ENTITY, "Unprocessable Entity"},
    {HttpResponseStatusCode::LOCKED, "Locked"},
    {HttpResponseStatusCode::FAILED_DEPENDENCY, "Failed Dependency"},
    {HttpResponseStatusCode::UNORDERED_COLLECTION, "Unordered Collection"},
    {HttpResponseStatusCode::UPGRADE_REQUIRED, "Upgrade Required"},
    {HttpResponseStatusCode::PRECONDITION_REQUIRED, "Precondition Required"},
    {HttpResponseStatusCode::TOO_MANY_REQUESTS, "Too Many Requests"},
    {HttpResponseStatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
                "Request Header Fields Too Large"},
    {HttpResponseStatusCode::NO_RESPONSE, "No Response"},
    {HttpResponseStatusCode::RETRY_WITH, "Retry With"},
    {HttpResponseStatusCode::CLIENT_CLOSED_REQUEST, "Client Closed Request"},

    // 5xx Internal Server Error
    {HttpResponseStatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error"},
    {HttpResponseStatusCode::NOT_IMPLEMENTED, "Not Implemented"},
    {HttpResponseStatusCode::BAD_GATEWAY, "Bad Gateway"},
    {HttpResponseStatusCode::SERVICE_UNAVAILABLE, "Service Unavailable"},
    {HttpResponseStatusCode::GATEWAY_TIMEOUT, "Gateway Timeout"},
    {HttpResponseStatusCode::HTTP_VERSION_NOT_SUPPORTED,
                "HTTP Version Not Supported"},
    {HttpResponseStatusCode::VARIANT_ALSO_NEGOTIATES,
                "Variant Also Negotiates"},
    {HttpResponseStatusCode::INSUFFICIENT_STORAGE, "Insufficient Storage"},
    {HttpResponseStatusCode::LOOP_DETECTED, "Loop Detected"},
    {HttpResponseStatusCode::BANDWIDTH_LIMIT_EXCEEDED,
                "Bandwidth Limit Exceeded"},
    {HttpResponseStatusCode::NOT_EXTENDED, "Not Extended"}
};

QByteArray reasonPhrase(HttpResponseStatusCode statusCode)
{
    return phrases[statusCode];
}

} // namespace Tufao
<|endoftext|>


<commit_before>#pragma once
/*
* Covariant Script Version Info
*
* 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.
*
* Copyright (C) 2018 Michael Lee(李登淳)
* Email: mikecovlee@163.com
* Github: https://github.com/mikecovlee
*
* Version Format:
*   1 . 0 . 0 [Version Code](Preview/Unstable/Stable) Build 1
*   |   |   |                           |
*   |   | Minor                       Status
*   | Major
* Master
*
*/
#define COVSCRIPT_VERSION_NUM 1,3,2,5
#define COVSCRIPT_VERSION_STR "1.3.2 Nautilus pompilius(Stable) Build 5"
#define COVSCRIPT_STD_VERSION 181001
#if defined(_WIN32) || defined(WIN32)
#define COVSCRIPT_PLATFORM_WIN32
#endif
<commit_msg>Hello, v3.0.0<commit_after>#pragma once
/*
* Covariant Script Version Info
*
* 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.
*
* Copyright (C) 2018 Michael Lee(李登淳)
* Email: mikecovlee@163.com
* Github: https://github.com/mikecovlee
*
* Version Format:
*   1 . 0 . 0 [Version Code](Preview/Unstable/Stable) Build 1
*   |   |   |                           |
*   |   | Minor                       Status
*   | Major
* Master
*
*/
#define COVSCRIPT_VERSION_NUM 3,0,0,1
#define COVSCRIPT_VERSION_STR "3.0.0 Pantholops hodgsonii(Preview) Build 1"
#define COVSCRIPT_STD_VERSION 190101
#if defined(_WIN32) || defined(WIN32)
#define COVSCRIPT_PLATFORM_WIN32
#endif
<|endoftext|>


<commit_before>/*
// Copyright (c) 2018 Intel Corporation
//
// 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.
*/

#include <boost/algorithm/string.hpp>
#include <boost/bimap.hpp>
#include <boost/container/flat_map.hpp>
#include <cstdio>
#include <cstring>
#include <exception>
#include <filesystem>
#include <ipmid/api.hpp>
#include <ipmid/types.hpp>
#include <map>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus/match.hpp>
#include <string>
#include <vector>

#pragma once

static constexpr bool debug = false;

struct CmpStrVersion
{
    bool operator()(std::string a, std::string b) const
    {
        return strverscmp(a.c_str(), b.c_str()) < 0;
    }
};

using SensorSubTree = boost::container::flat_map<
    std::string,
    boost::container::flat_map<std::string, std::vector<std::string>>,
    CmpStrVersion>;

using SensorNumMap = boost::bimap<int, std::string>;

static constexpr uint16_t maxSensorsPerLUN = 255;
static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
static constexpr uint16_t lun1Sensor0 = 0x100;
static constexpr uint16_t lun3Sensor0 = 0x300;
static constexpr uint16_t invalidSensorNumber = 0xFFFF;
static constexpr uint8_t reservedSensorNumber = 0xFF;

namespace details
{
// Enable/disable the logging of stats instrumentation
static constexpr bool enableInstrumentation = false;

class IPMIStatsEntry
{
  private:
    int numReadings = 0;
    int numMissings = 0;
    int numStreakRead = 0;
    int numStreakMiss = 0;
    double minValue = 0.0;
    double maxValue = 0.0;
    std::string sensorName;

  public:
    const std::string& getName(void) const
    {
        return sensorName;
    }

    void updateName(std::string_view name)
    {
        sensorName = name;
    }

    // Returns true if this is the first successful reading
    // This is so the caller can log the coefficients used
    bool updateReading(double reading, int raw)
    {
        if constexpr (!enableInstrumentation)
        {
            return false;
        }

        bool first = ((numReadings == 0) && (numMissings == 0));

        // Sensors can use "nan" to indicate unavailable reading
        if (!(std::isfinite(reading)))
        {
            // Only show this if beginning a new streak
            if (numStreakMiss == 0)
            {
                std::cerr << "IPMI sensor " << sensorName
                          << ": Missing reading, byte=" << raw
                          << ", Reading counts good=" << numReadings
                          << " miss=" << numMissings
                          << ", Prior good streak=" << numStreakRead << "\n";
            }

            numStreakRead = 0;
            ++numMissings;
            ++numStreakMiss;

            return first;
        }

        // Only show this if beginning a new streak and not the first time
        if ((numStreakRead == 0) && (numReadings != 0))
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": Recovered reading, value=" << reading
                      << " byte=" << raw
                      << ", Reading counts good=" << numReadings
                      << " miss=" << numMissings
                      << ", Prior miss streak=" << numStreakMiss << "\n";
        }

        // Initialize min/max if the first successful reading
        if (numReadings == 0)
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": First reading, value=" << reading << " byte=" << raw
                      << "\n";

            minValue = reading;
            maxValue = reading;
        }

        numStreakMiss = 0;
        ++numReadings;
        ++numStreakRead;

        // Only provide subsequent output if new min/max established
        if (reading < minValue)
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": Lowest reading, value=" << reading
                      << " byte=" << raw << "\n";

            minValue = reading;
        }

        if (reading > maxValue)
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": Highest reading, value=" << reading
                      << " byte=" << raw << "\n";

            maxValue = reading;
        }

        return first;
    }
};

class IPMIStatsTable
{
  private:
    std::vector<IPMIStatsEntry> entries;

  private:
    void padEntries(size_t index)
    {
        char hexbuf[16];

        // Pad vector until entries[index] becomes a valid index
        while (entries.size() <= index)
        {
            // As name not known yet, use human-readable hex as name
            IPMIStatsEntry newEntry;
            sprintf(hexbuf, "0x%02zX", entries.size());
            newEntry.updateName(hexbuf);

            entries.push_back(std::move(newEntry));
        }
    }

  public:
    void wipeTable(void)
    {
        entries.clear();
    }

    const std::string& getName(size_t index)
    {
        padEntries(index);
        return entries[index].getName();
    }

    void updateName(size_t index, std::string_view name)
    {
        padEntries(index);
        entries[index].updateName(name);
    }

    bool updateReading(size_t index, double reading, int raw)
    {
        padEntries(index);
        return entries[index].updateReading(reading, raw);
    }
};

class IPMIWriteEntry
{
  private:
    bool writePermission = false;

  public:
    bool getWritePermission(void) const
    {
        return writePermission;
    }

    void setWritePermission(bool permission)
    {
        writePermission = permission;
    }
};

class IPMIWriteTable
{
  private:
    std::vector<IPMIWriteEntry> entries;

  private:
    void padEntries(size_t index)
    {
        // Pad vector until entries[index] becomes a valid index
        if (entries.size() <= index)
        {
            entries.resize(index + 1);
        }
    }

  public:
    void wipeTable(void)
    {
        entries.clear();
    }

    bool getWritePermission(size_t index)
    {
        padEntries(index);
        return entries[index].getWritePermission();
    }

    void setWritePermission(size_t index, bool permission)
    {
        padEntries(index);
        entries[index].setWritePermission(permission);
    }
};

// Store information for threshold sensors and they are not used by VR
// sensors. These objects are global singletons, used from a variety of places.
inline IPMIStatsTable sdrStatsTable;
inline IPMIWriteTable sdrWriteTable;

/**
 * Search ObjectMapper for sensors and update them to subtree.
 *
 * The function will search for sensors under either
 * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
 * optionally search VR typed sensors under /xyz/openbmc_project/vr
 *
 * @return the updated amount of times any of "sensors" or "extsensors" sensor
 * paths updated successfully, previous amount if all failed. The "vr"
 * sensor path is optional, and does not participate in the return value.
 */
uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);

bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
} // namespace details

bool getSensorSubtree(SensorSubTree& subtree);

#ifdef FEATURE_HYBRID_SENSORS
ipmi::sensor::IdInfoMap::const_iterator
    findStaticSensor(const std::string& path);
#endif

struct CmpStr
{
    bool operator()(const char* a, const char* b) const
    {
        return std::strcmp(a, b) < 0;
    }
};

static constexpr size_t sensorTypeCodes = 0;
static constexpr size_t sensorEventTypeCodes = 1;

enum class SensorTypeCodes : uint8_t
{
    reserved = 0x0,
    temperature = 0x1,
    voltage = 0x2,
    current = 0x3,
    fan = 0x4,
    other = 0xB,
    memory = 0x0c,
    power_unit = 0x09,
    buttons = 0x14,
    watchdog2 = 0x23,
};

enum class SensorEventTypeCodes : uint8_t
{
    unspecified = 0x00,
    threshold = 0x01,
    sensorSpecified = 0x6f
};

const static boost::container::flat_map<
    const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
    sensorTypes{
        {{"temperature", std::make_pair(SensorTypeCodes::temperature,
                                        SensorEventTypeCodes::threshold)},
         {"voltage", std::make_pair(SensorTypeCodes::voltage,
                                    SensorEventTypeCodes::threshold)},
         {"current", std::make_pair(SensorTypeCodes::current,
                                    SensorEventTypeCodes::threshold)},
         {"fan_tach", std::make_pair(SensorTypeCodes::fan,
                                     SensorEventTypeCodes::threshold)},
         {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
                                    SensorEventTypeCodes::threshold)},
         {"power", std::make_pair(SensorTypeCodes::other,
                                  SensorEventTypeCodes::threshold)},
         {"memory", std::make_pair(SensorTypeCodes::memory,
                                   SensorEventTypeCodes::sensorSpecified)},
         {"state", std::make_pair(SensorTypeCodes::power_unit,
                                  SensorEventTypeCodes::sensorSpecified)},
         {"buttons", std::make_pair(SensorTypeCodes::buttons,
                                    SensorEventTypeCodes::sensorSpecified)},
         {"watchdog", std::make_pair(SensorTypeCodes::watchdog2,
                                     SensorEventTypeCodes::sensorSpecified)}}};

std::string getSensorTypeStringFromPath(const std::string& path);

uint8_t getSensorTypeFromPath(const std::string& path);

uint16_t getSensorNumberFromPath(const std::string& path);

uint8_t getSensorEventTypeFromPath(const std::string& path);

std::string getPathFromSensorNumber(uint16_t sensorNum);

namespace ipmi
{
std::map<std::string, std::vector<std::string>>
    getObjectInterfaces(const char* path);

std::map<std::string, Value> getEntityManagerProperties(const char* path,
                                                        const char* interface);

const std::string* getSensorConfigurationInterface(
    const std::map<std::string, std::vector<std::string>>&
        sensorInterfacesResponse);

void updateIpmiFromAssociation(const std::string& path,
                               const DbusInterfaceMap& sensorMap,
                               uint8_t& entityId, uint8_t& entityInstance);
} // namespace ipmi
<commit_msg>dbus-sdr: Add processor sensor type<commit_after>/*
// Copyright (c) 2018 Intel Corporation
//
// 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.
*/

#include <boost/algorithm/string.hpp>
#include <boost/bimap.hpp>
#include <boost/container/flat_map.hpp>
#include <cstdio>
#include <cstring>
#include <exception>
#include <filesystem>
#include <ipmid/api.hpp>
#include <ipmid/types.hpp>
#include <map>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus/match.hpp>
#include <string>
#include <vector>

#pragma once

static constexpr bool debug = false;

struct CmpStrVersion
{
    bool operator()(std::string a, std::string b) const
    {
        return strverscmp(a.c_str(), b.c_str()) < 0;
    }
};

using SensorSubTree = boost::container::flat_map<
    std::string,
    boost::container::flat_map<std::string, std::vector<std::string>>,
    CmpStrVersion>;

using SensorNumMap = boost::bimap<int, std::string>;

static constexpr uint16_t maxSensorsPerLUN = 255;
static constexpr uint16_t maxIPMISensors = (maxSensorsPerLUN * 3);
static constexpr uint16_t lun1Sensor0 = 0x100;
static constexpr uint16_t lun3Sensor0 = 0x300;
static constexpr uint16_t invalidSensorNumber = 0xFFFF;
static constexpr uint8_t reservedSensorNumber = 0xFF;

namespace details
{
// Enable/disable the logging of stats instrumentation
static constexpr bool enableInstrumentation = false;

class IPMIStatsEntry
{
  private:
    int numReadings = 0;
    int numMissings = 0;
    int numStreakRead = 0;
    int numStreakMiss = 0;
    double minValue = 0.0;
    double maxValue = 0.0;
    std::string sensorName;

  public:
    const std::string& getName(void) const
    {
        return sensorName;
    }

    void updateName(std::string_view name)
    {
        sensorName = name;
    }

    // Returns true if this is the first successful reading
    // This is so the caller can log the coefficients used
    bool updateReading(double reading, int raw)
    {
        if constexpr (!enableInstrumentation)
        {
            return false;
        }

        bool first = ((numReadings == 0) && (numMissings == 0));

        // Sensors can use "nan" to indicate unavailable reading
        if (!(std::isfinite(reading)))
        {
            // Only show this if beginning a new streak
            if (numStreakMiss == 0)
            {
                std::cerr << "IPMI sensor " << sensorName
                          << ": Missing reading, byte=" << raw
                          << ", Reading counts good=" << numReadings
                          << " miss=" << numMissings
                          << ", Prior good streak=" << numStreakRead << "\n";
            }

            numStreakRead = 0;
            ++numMissings;
            ++numStreakMiss;

            return first;
        }

        // Only show this if beginning a new streak and not the first time
        if ((numStreakRead == 0) && (numReadings != 0))
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": Recovered reading, value=" << reading
                      << " byte=" << raw
                      << ", Reading counts good=" << numReadings
                      << " miss=" << numMissings
                      << ", Prior miss streak=" << numStreakMiss << "\n";
        }

        // Initialize min/max if the first successful reading
        if (numReadings == 0)
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": First reading, value=" << reading << " byte=" << raw
                      << "\n";

            minValue = reading;
            maxValue = reading;
        }

        numStreakMiss = 0;
        ++numReadings;
        ++numStreakRead;

        // Only provide subsequent output if new min/max established
        if (reading < minValue)
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": Lowest reading, value=" << reading
                      << " byte=" << raw << "\n";

            minValue = reading;
        }

        if (reading > maxValue)
        {
            std::cerr << "IPMI sensor " << sensorName
                      << ": Highest reading, value=" << reading
                      << " byte=" << raw << "\n";

            maxValue = reading;
        }

        return first;
    }
};

class IPMIStatsTable
{
  private:
    std::vector<IPMIStatsEntry> entries;

  private:
    void padEntries(size_t index)
    {
        char hexbuf[16];

        // Pad vector until entries[index] becomes a valid index
        while (entries.size() <= index)
        {
            // As name not known yet, use human-readable hex as name
            IPMIStatsEntry newEntry;
            sprintf(hexbuf, "0x%02zX", entries.size());
            newEntry.updateName(hexbuf);

            entries.push_back(std::move(newEntry));
        }
    }

  public:
    void wipeTable(void)
    {
        entries.clear();
    }

    const std::string& getName(size_t index)
    {
        padEntries(index);
        return entries[index].getName();
    }

    void updateName(size_t index, std::string_view name)
    {
        padEntries(index);
        entries[index].updateName(name);
    }

    bool updateReading(size_t index, double reading, int raw)
    {
        padEntries(index);
        return entries[index].updateReading(reading, raw);
    }
};

class IPMIWriteEntry
{
  private:
    bool writePermission = false;

  public:
    bool getWritePermission(void) const
    {
        return writePermission;
    }

    void setWritePermission(bool permission)
    {
        writePermission = permission;
    }
};

class IPMIWriteTable
{
  private:
    std::vector<IPMIWriteEntry> entries;

  private:
    void padEntries(size_t index)
    {
        // Pad vector until entries[index] becomes a valid index
        if (entries.size() <= index)
        {
            entries.resize(index + 1);
        }
    }

  public:
    void wipeTable(void)
    {
        entries.clear();
    }

    bool getWritePermission(size_t index)
    {
        padEntries(index);
        return entries[index].getWritePermission();
    }

    void setWritePermission(size_t index, bool permission)
    {
        padEntries(index);
        entries[index].setWritePermission(permission);
    }
};

// Store information for threshold sensors and they are not used by VR
// sensors. These objects are global singletons, used from a variety of places.
inline IPMIStatsTable sdrStatsTable;
inline IPMIWriteTable sdrWriteTable;

/**
 * Search ObjectMapper for sensors and update them to subtree.
 *
 * The function will search for sensors under either
 * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
 * optionally search VR typed sensors under /xyz/openbmc_project/vr
 *
 * @return the updated amount of times any of "sensors" or "extsensors" sensor
 * paths updated successfully, previous amount if all failed. The "vr"
 * sensor path is optional, and does not participate in the return value.
 */
uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);

bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);
} // namespace details

bool getSensorSubtree(SensorSubTree& subtree);

#ifdef FEATURE_HYBRID_SENSORS
ipmi::sensor::IdInfoMap::const_iterator
    findStaticSensor(const std::string& path);
#endif

struct CmpStr
{
    bool operator()(const char* a, const char* b) const
    {
        return std::strcmp(a, b) < 0;
    }
};

static constexpr size_t sensorTypeCodes = 0;
static constexpr size_t sensorEventTypeCodes = 1;

enum class SensorTypeCodes : uint8_t
{
    reserved = 0x00,
    temperature = 0x01,
    voltage = 0x02,
    current = 0x03,
    fan = 0x04,
    processor = 0x07,
    power_unit = 0x09,
    other = 0x0b,
    memory = 0x0c,
    buttons = 0x14,
    watchdog2 = 0x23,
};

enum class SensorEventTypeCodes : uint8_t
{
    unspecified = 0x00,
    threshold = 0x01,
    sensorSpecified = 0x6f
};

const static boost::container::flat_map<
    const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
    sensorTypes{
        {{"temperature", std::make_pair(SensorTypeCodes::temperature,
                                        SensorEventTypeCodes::threshold)},
         {"voltage", std::make_pair(SensorTypeCodes::voltage,
                                    SensorEventTypeCodes::threshold)},
         {"current", std::make_pair(SensorTypeCodes::current,
                                    SensorEventTypeCodes::threshold)},
         {"fan_tach", std::make_pair(SensorTypeCodes::fan,
                                     SensorEventTypeCodes::threshold)},
         {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
                                    SensorEventTypeCodes::threshold)},
         {"processor", std::make_pair(SensorTypeCodes::processor,
                                      SensorEventTypeCodes::sensorSpecified)},
         {"power", std::make_pair(SensorTypeCodes::other,
                                  SensorEventTypeCodes::threshold)},
         {"memory", std::make_pair(SensorTypeCodes::memory,
                                   SensorEventTypeCodes::sensorSpecified)},
         {"state", std::make_pair(SensorTypeCodes::power_unit,
                                  SensorEventTypeCodes::sensorSpecified)},
         {"buttons", std::make_pair(SensorTypeCodes::buttons,
                                    SensorEventTypeCodes::sensorSpecified)},
         {"watchdog", std::make_pair(SensorTypeCodes::watchdog2,
                                     SensorEventTypeCodes::sensorSpecified)}}};

std::string getSensorTypeStringFromPath(const std::string& path);

uint8_t getSensorTypeFromPath(const std::string& path);

uint16_t getSensorNumberFromPath(const std::string& path);

uint8_t getSensorEventTypeFromPath(const std::string& path);

std::string getPathFromSensorNumber(uint16_t sensorNum);

namespace ipmi
{
std::map<std::string, std::vector<std::string>>
    getObjectInterfaces(const char* path);

std::map<std::string, Value> getEntityManagerProperties(const char* path,
                                                        const char* interface);

const std::string* getSensorConfigurationInterface(
    const std::map<std::string, std::vector<std::string>>&
        sensorInterfacesResponse);

void updateIpmiFromAssociation(const std::string& path,
                               const DbusInterfaceMap& sensorMap,
                               uint8_t& entityId, uint8_t& entityInstance);
} // namespace ipmi
<|endoftext|>


<commit_before>/**
 \file
 Implementation of the Corsika shower reader

 \author Lukas Nellen
 \version $Id$
 \date 29 Jan 2004
 */

#include <corsika/Constants.h>
#include <corsika/ShowerFile.h>
#include <corsika/ShowerParticleStream.h>
#include <corsika/IOException.h>
#include <corsika/Block.h>
#include <corsika/Shower.h>
#include <corsika/LongFile.h>
#include <corsika/LongProfile.h>
#include <corsika/particle/ParticleList.h>

#include <sstream>
#include <string>
#include <cmath>
#include <iostream>

#include <boost/tokenizer.hpp>
#include <boost/filesystem.hpp>

using namespace std;
using namespace corsika;

namespace bfs = boost::filesystem;

typedef boost::tokenizer<boost::char_separator<char> > mytok;

static void log(const std::string& mess)
{
    std::cout << mess << std::endl;
}
static void log(const std::ostringstream& mess)
{
    std::cout << mess.str() << std::endl;
}

#define INFO(mess) log(mess);
#define ERROR(mess) log(mess);
#define FATAL(mess) log(mess);

ShowerFile::ShowerFile() :
    fRawStream(),
    fCurrentPosition(0),
    fObservationLevel(1),
    fIsThinned(true),
    fFileScanned(false)
{}

ShowerFile::ShowerFile(const std::string& theFileName, bool requireParticleFile) :
fRawStream(),
fCurrentPosition(0),
fObservationLevel(1),
fIsThinned(true),
fFileScanned(false)
{
    // only call Open() if the particle file is required (default behaviour)
    if (requireParticleFile) Open(theFileName);
}

void ShowerFile::Open(const std::string& theFileName, bool scan)
{
    Close();

    // Compute the name for the long file
    string file = theFileName;

    bfs::path p(theFileName);
    p.replace_extension(".long");
    fLongFile = p.string();

    p = bfs::path(fLongFile);
    if ( !(bfs::exists(p) && bfs::is_regular_file(p)) ) fLongFile = "";

    fRawStream = RawStream::Create(theFileName);
    fIsThinned = fRawStream->IsThinned();
    if (scan && fRawStream->IsSeekable())
    {
        fIndex.Scan(*fRawStream, false);
        fFileScanned = true;
    }
    else if (!fRawStream->IsSeekable())
    {
        ostringstream msg;
        msg << "File " << theFileName << " does not support random access. This class can not handle it";
        throw IOException(msg.str());
    }
    if (fIsThinned) ReadRunHeader<Thinned>();
    else ReadRunHeader<NotThinned>();
}

void ShowerFile::Close()
{
    fRunHeader = corsika::RunHeader();
    fRawStream.reset();

    fIndex.eventHeaders.clear();
    fIndex.eventTrailers.clear();
    fIndex.longBlocks.clear();
    fIndex.IDToPosition.clear();
}

template <class Thinning> Status ShowerFile::Read()
{
    if (!fRawStream || fCurrentPosition >= fIndex.eventHeaders.size())
        return eEOF;

    fRawStream->SeekTo(fIndex.eventHeaders[fCurrentPosition]);

    Block<Thinning> headerBlock;
    if (!fRawStream->GetNextBlock(headerBlock))
    {
        ostringstream err;
        err << "Cannot read CORSIKA shower header for position "
        << fCurrentPosition;
        FATAL(err);
        return eFail;
    }

    if (!headerBlock.IsEventHeader())
    {
        ostringstream err;
        err << "First block at position " << fCurrentPosition
        << " is not event header";
        FATAL(err);
        return eFail;
    }
    const EventHeader& header = headerBlock.AsEventHeader;

    fRawStream->SeekTo(fIndex.eventTrailers[fCurrentPosition]);

    Block<Thinning> trailerBlock;
    if (!fRawStream->GetNextBlock(trailerBlock))
    {
        ostringstream err;
        err << "Cannot read CORSIKA shower trailer for position "
        << fCurrentPosition;
        FATAL(err);
        return eFail;
    }
    if (!trailerBlock.IsEventTrailer())
    {
        ostringstream err;
        err << "Block at position " << fCurrentPosition
        << " is not event trailer";
        FATAL(err);
        return eFail;
    }

    const EventTrailer& trailer = trailerBlock.AsEventTrailer;

    if (fObservationLevel > header.fObservationLevels)
    {
        ostringstream info;
        info << "The requested observation level: " << fObservationLevel
        << " does not exist (max obs. level: "
        << header.fObservationLevels << "), "
        << "switching to level 1.";
        fObservationLevel = 1;
        INFO(info);
    }

    // Corsika starts at the top of the atmosphere, not
    const float heightObsLevel =
    header.fObservationHeight[int(header.fObservationLevels) - 1]; // in cm
    const float heightFirstInt = abs(header.fZFirst); // in cm

    double hReference;
    const double hAtmBoundary = (header.fStartingHeight>0? header.fStartingHeight: 112.8292*1e5); // in cm

    // for the SLANT and CURVED options, clock starts at the margin of
    // the atmosphere. This is indicated by fZFirst < 0
    if (header.fZFirst < 0.) hReference = hAtmBoundary;
    else hReference = heightFirstInt;

    double timeShift = 0;

    const double Zenith = header.fTheta;
    const double cosZenith = cos(Zenith);

    if (header.fFlagCurved)
    {

        INFO("CURVED version");

        if (ParticleList::CorsikaToPDG(int(header.fParticleId)) == Particle::ePhoton)
            hReference = heightFirstInt;

        timeShift = (pow((kEarthRadius + heightObsLevel)*cosZenith, 2) +
                     pow(hReference - heightObsLevel, 2) +
                     2*(kEarthRadius + heightObsLevel)*(hReference - heightObsLevel));
        timeShift = sqrt(timeShift);
        timeShift -= (kEarthRadius + heightObsLevel)*cosZenith;
        timeShift /= kSpeedOfLight;

        ostringstream info;
        info << "TimeShift to core: " << timeShift/1e9; // output in ns
        INFO(info);

    }
    else
        timeShift = (hReference - heightObsLevel) / (cosZenith * kSpeedOfLight);

    ShowerParticleStream* particleIterator =
    new ShowerParticleStream(fRawStream,
                             fIndex.eventHeaders[fCurrentPosition] + 1,
                             timeShift,
                             fObservationLevel,
                             true); // last one is keepMuProd
    fCurrentShower = Shower(header, trailer, particleIterator);

    if (fIndex.longBlocks.size() > 0)
        ReadLongBlocks<Thinning>();
    else if ( fLongFile != "" )
        ReadLongFile();

    ++fCurrentPosition;

    return eSuccess;
}

template <class Thinning> Status ShowerFile::ReadRunHeader()
{
    Block<Thinning> runHeaderBlock;
    if (!fRawStream->GetNextBlock(runHeaderBlock))
    {
        FATAL("Cannot read CORSIKA run header");
        return eFail;
    }
    if (!runHeaderBlock.IsRunHeader())
    {
        FATAL("First block is not a run header");
        return eFail;
    }
    fRunHeader = runHeaderBlock.AsRunHeader;
    return eSuccess;
}

Status ShowerFile::FindEvent(const unsigned int eventId)
{
    if (!IsOpen()) return eEOF;
    const IdToPositionMap::const_iterator iter = fIndex.IDToPosition.find(eventId);
    if (iter == fIndex.IDToPosition.end() || iter->second >= fIndex.eventHeaders.size())
        return eFail;

    fCurrentPosition = iter->second;
    if (fIsThinned) return Read<Thinned>();
    return Read<NotThinned>();
}

size_t ShowerFile::GetNEvents()
{
    if (!fRawStream) throw IOException("Cannot request number of events from closed file");
    if (!fRawStream->IsSeekable()) throw IOException("Cannot request number of events for this file. It is not seekable.");

    if (!fFileScanned)
    {
        fIndex.Scan(*fRawStream, false);
        fFileScanned = true;
    }
    return fIndex.IDToPosition.size();
}

Status ShowerFile::ReadLongFile()
{
    //cout << "reading long file " << fLongFile << endl;
    if (!fCorsikaLongFile)
        fCorsikaLongFile.reset(new LongFile(fLongFile, GetCurrentShower().GetZenith()));

    if (fCorsikaLongFile->size() >= fCurrentPosition)
    {
        LongProfile p = fCorsikaLongFile->GetProfile(fCurrentPosition);
        fCurrentShower.fdEdX = p.fdEdX;
        fCurrentShower.fChargeProfile = p.fChargeProfile;
        fCurrentShower.fGammaProfile = p.fGammaProfile;
        fCurrentShower.fElectronProfile = p.fElectronProfile;
        fCurrentShower.fPositronProfile = p.fPositronProfile;
        fCurrentShower.fMuonProfile = p.fMuonProfile;
        fCurrentShower.fAntiMuonProfile = p.fAntiMuonProfile;
        fCurrentShower.fHadronProfile = p.fHadronProfile;
        fCurrentShower.fNucleiProfile = p.fNucleiProfile;
        fCurrentShower.fCherenkovProfile = p.fCherenkovProfile;
        fCurrentShower.fDepth_dE = p.fDepth_dE;
        fCurrentShower.fDepth = p.fDepth;

        fCurrentShower.SetGaisserHillasParams(p.fGaisserHillas);
        fCurrentShower.SetCalorimetricEnergy(p.fCalorimetricEnergy);
    }
    else
    {
        fCurrentShower.fdEdX.clear();
        fCurrentShower.fChargeProfile.clear();
        fCurrentShower.fGammaProfile.clear();
        fCurrentShower.fElectronProfile.clear();
        fCurrentShower.fPositronProfile.clear();
        fCurrentShower.fMuonProfile.clear();
        fCurrentShower.fAntiMuonProfile.clear();
        fCurrentShower.fHadronProfile.clear();
        fCurrentShower.fNucleiProfile.clear();
        fCurrentShower.fCherenkovProfile.clear();
        fCurrentShower.fDepth_dE.clear();
        fCurrentShower.fDepth.clear();

        fCurrentShower.SetCalorimetricEnergy(0);

        GaisserHillasParameter gh;
        fCurrentShower.SetGaisserHillasParams(gh);
    }
    return eSuccess;
}

template <class Thinning> Status ShowerFile::ReadLongBlocks()
{
    fRawStream->SeekTo(fIndex.longBlocks[fCurrentPosition]);

    Block<Thinning> block;
    if (!fRawStream->GetNextBlock(block))
    {
        ostringstream err;
        err << "Cannot read CORSIKA long block at position "
        << fCurrentPosition;
        FATAL(err);
        return eFail;
    }

    if (!block.IsLongitudinal())
    {
        ostringstream err;
        err << "Block at position " << fCurrentPosition
        << " is not longitudinal";
        FATAL(err);
        return eFail;
    }
    const LongitudinalBlock& longBlock = block.AsLongitudinalBlock;

    vector<double> auxDeltaEn;
    vector<double> auxCharge;
    vector<double> auxGammas;
    vector<double> auxElectrons;
    vector<double> auxPositrons;
    vector<double> auxMuons;
    vector<double> auxAntiMuons;
    vector<double> auxHadrons;
    vector<double> auxNuclei;
    vector<double> auxCherenkov;
    vector<double> auxDepth_dE;
    vector<double> auxDepth;

    const int nBlocks = int(longBlock.fStepsAndBlocks)%100;
    //cout << int(longBlock.fStepsAndBlocks/100)<< " steps in " << nBlocks << " blocks" << endl;
    int i = 0;

    for (; i != kLongEntriesPerBlock; ++i)
    {
        if (i && !longBlock.fEntries[i].fDepth)
            break;
        auxDeltaEn.push_back(0);
        auxCharge.push_back(longBlock.fEntries[i].fCharged);
        auxGammas.push_back(longBlock.fEntries[i].fGamma);
        auxElectrons.push_back(longBlock.fEntries[i].fEminus);
        auxPositrons.push_back(longBlock.fEntries[i].fEplus);
        auxMuons.push_back(longBlock.fEntries[i].fMuMinus);
        auxAntiMuons.push_back(longBlock.fEntries[i].fMuPlus);
        auxHadrons.push_back(longBlock.fEntries[i].fNuclei);
        auxNuclei.push_back(longBlock.fEntries[i].fHadron);
        auxCherenkov.push_back(longBlock.fEntries[i].fCherenkov);
        auxDepth.push_back(longBlock.fEntries[i].fDepth);
        auxDepth_dE.push_back(longBlock.fEntries[i].fDepth);
    }

    for (int b = 1; b < nBlocks; ++b)
    {
        if (!fRawStream->GetNextBlock(block))
        {
            ostringstream err;
            err << "Cannot read CORSIKA long block #" << b << "at position "
            << fCurrentPosition;
            FATAL(err);
            return eFail;
        }
        const LongitudinalBlock& longBlock = block.AsLongitudinalBlock;
        for (int j = 0; j != kLongEntriesPerBlock; ++j,++i)
        {
            if (i && !longBlock.fEntries[j].fDepth)
                break;
            auxDeltaEn.push_back(0);
            auxCharge.push_back(longBlock.fEntries[j].fCharged);
            auxGammas.push_back(longBlock.fEntries[j].fGamma);
            auxElectrons.push_back(longBlock.fEntries[j].fEminus);
            auxPositrons.push_back(longBlock.fEntries[i].fEplus);
            auxMuons.push_back(longBlock.fEntries[i].fMuMinus);
            auxAntiMuons.push_back(longBlock.fEntries[i].fMuPlus);
            auxHadrons.push_back(longBlock.fEntries[i].fNuclei);
            auxNuclei.push_back(longBlock.fEntries[i].fHadron);
            auxCherenkov.push_back(longBlock.fEntries[i].fCherenkov);
            auxDepth.push_back(longBlock.fEntries[j].fDepth);
            auxDepth_dE.push_back(longBlock.fEntries[j].fDepth);
        }
    }
    //cout << i << " entries read" << endl;

    fCurrentShower.fdEdX = auxDeltaEn;
    fCurrentShower.fChargeProfile = auxCharge;
    fCurrentShower.fGammaProfile = auxGammas;
    fCurrentShower.fElectronProfile = auxElectrons;
    fCurrentShower.fPositronProfile = auxPositrons;
    fCurrentShower.fMuonProfile = auxMuons;
    fCurrentShower.fAntiMuonProfile = auxAntiMuons;
    fCurrentShower.fHadronProfile = auxHadrons;
    fCurrentShower.fNucleiProfile = auxNuclei;
    fCurrentShower.fCherenkovProfile = auxCherenkov;
    fCurrentShower.fDepth_dE = auxDepth_dE;
    fCurrentShower.fDepth = auxDepth;

    // fCurrentShower.SetGaisserHillasParams(gh);
    // fCurrentShower.SetCalorimetricEnergy(energyDepositSum);

    return eSuccess;
}
<commit_msg>bug fix<commit_after>/**
 \file
 Implementation of the Corsika shower reader

 \author Lukas Nellen
 \version $Id$
 \date 29 Jan 2004
 */

#include <corsika/Constants.h>
#include <corsika/ShowerFile.h>
#include <corsika/ShowerParticleStream.h>
#include <corsika/IOException.h>
#include <corsika/Block.h>
#include <corsika/Shower.h>
#include <corsika/LongFile.h>
#include <corsika/LongProfile.h>
#include <corsika/particle/ParticleList.h>

#include <sstream>
#include <string>
#include <cmath>
#include <iostream>

#include <boost/tokenizer.hpp>
#include <boost/filesystem.hpp>

using namespace std;
using namespace corsika;

namespace bfs = boost::filesystem;

typedef boost::tokenizer<boost::char_separator<char> > mytok;

static void log(const std::string& mess)
{
    std::cout << mess << std::endl;
}
static void log(const std::ostringstream& mess)
{
    std::cout << mess.str() << std::endl;
}

#define INFO(mess) log(mess);
#define ERROR(mess) log(mess);
#define FATAL(mess) log(mess);

ShowerFile::ShowerFile() :
    fRawStream(),
    fCurrentPosition(0),
    fObservationLevel(1),
    fIsThinned(true),
    fFileScanned(false)
{}

ShowerFile::ShowerFile(const std::string& theFileName, bool requireParticleFile) :
fRawStream(),
fCurrentPosition(0),
fObservationLevel(1),
fIsThinned(true),
fFileScanned(false)
{
    // only call Open() if the particle file is required (default behaviour)
    if (requireParticleFile) Open(theFileName);
}

void ShowerFile::Open(const std::string& theFileName, bool scan)
{
    Close();

    // Compute the name for the long file
    string file = theFileName;

    bfs::path p(theFileName);
    p.replace_extension(".long");
    fLongFile = p.string();

    p = bfs::path(fLongFile);
    if ( !(bfs::exists(p) && bfs::is_regular_file(p)) ) fLongFile = "";

    fRawStream = RawStream::Create(theFileName);
    fIsThinned = fRawStream->IsThinned();
    if (scan && fRawStream->IsSeekable())
    {
        fIndex.Scan(*fRawStream, false);
        fFileScanned = true;
    }
    else if (!fRawStream->IsSeekable())
    {
        ostringstream msg;
        msg << "File " << theFileName << " does not support random access. This class can not handle it";
        throw IOException(msg.str());
    }
    if (fIsThinned) ReadRunHeader<Thinned>();
    else ReadRunHeader<NotThinned>();
}

void ShowerFile::Close()
{
    fRunHeader = corsika::RunHeader();
    fRawStream.reset();

    fIndex.eventHeaders.clear();
    fIndex.eventTrailers.clear();
    fIndex.longBlocks.clear();
    fIndex.IDToPosition.clear();
}

template <class Thinning> Status ShowerFile::Read()
{
    if (!fRawStream || fCurrentPosition >= fIndex.eventHeaders.size())
        return eEOF;

    fRawStream->SeekTo(fIndex.eventHeaders[fCurrentPosition]);

    Block<Thinning> headerBlock;
    if (!fRawStream->GetNextBlock(headerBlock))
    {
        ostringstream err;
        err << "Cannot read CORSIKA shower header for position "
        << fCurrentPosition;
        FATAL(err);
        return eFail;
    }

    if (!headerBlock.IsEventHeader())
    {
        ostringstream err;
        err << "First block at position " << fCurrentPosition
        << " is not event header";
        FATAL(err);
        return eFail;
    }
    const EventHeader& header = headerBlock.AsEventHeader;

    fRawStream->SeekTo(fIndex.eventTrailers[fCurrentPosition]);

    Block<Thinning> trailerBlock;
    if (!fRawStream->GetNextBlock(trailerBlock))
    {
        ostringstream err;
        err << "Cannot read CORSIKA shower trailer for position "
        << fCurrentPosition;
        FATAL(err);
        return eFail;
    }
    if (!trailerBlock.IsEventTrailer())
    {
        ostringstream err;
        err << "Block at position " << fCurrentPosition
        << " is not event trailer";
        FATAL(err);
        return eFail;
    }

    const EventTrailer& trailer = trailerBlock.AsEventTrailer;

    if (fObservationLevel > header.fObservationLevels)
    {
        ostringstream info;
        info << "The requested observation level: " << fObservationLevel
        << " does not exist (max obs. level: "
        << header.fObservationLevels << "), "
        << "switching to level 1.";
        fObservationLevel = 1;
        INFO(info);
    }

    // Corsika starts at the top of the atmosphere, not
    const float heightObsLevel =
    header.fObservationHeight[int(header.fObservationLevels) - 1]; // in cm
    const float heightFirstInt = abs(header.fZFirst); // in cm

    double hReference;
    const double hAtmBoundary = (header.fStartingHeight>0? header.fStartingHeight: 112.8292*1e5); // in cm

    // for the SLANT and CURVED options, clock starts at the margin of
    // the atmosphere. This is indicated by fZFirst < 0
    if (header.fZFirst < 0.) hReference = hAtmBoundary;
    else hReference = heightFirstInt;

    double timeShift = 0;

    const double Zenith = header.fTheta;
    const double cosZenith = cos(Zenith);

    if (header.fFlagCurved)
    {

        INFO("CURVED version");

        if (ParticleList::CorsikaToPDG(int(header.fParticleId)) == Particle::ePhoton)
            hReference = heightFirstInt;

        timeShift = (pow((kEarthRadius + heightObsLevel)*cosZenith, 2) +
                     pow(hReference - heightObsLevel, 2) +
                     2*(kEarthRadius + heightObsLevel)*(hReference - heightObsLevel));
        timeShift = sqrt(timeShift);
        timeShift -= (kEarthRadius + heightObsLevel)*cosZenith;
        timeShift /= kSpeedOfLight;

        ostringstream info;
        info << "TimeShift to core: " << timeShift/1e9; // output in ns
        INFO(info);

    }
    else
        timeShift = (hReference - heightObsLevel) / (cosZenith * kSpeedOfLight);

    ShowerParticleStream* particleIterator =
    new ShowerParticleStream(fRawStream,
                             fIndex.eventHeaders[fCurrentPosition] + 1,
                             timeShift,
                             fObservationLevel,
                             true); // last one is keepMuProd
    fCurrentShower = Shower(header, trailer, particleIterator);

    if (fIndex.longBlocks.size() > 0)
        ReadLongBlocks<Thinning>();
    else if ( fLongFile != "" )
        ReadLongFile();

    ++fCurrentPosition;

    return eSuccess;
}

template <class Thinning> Status ShowerFile::ReadRunHeader()
{
    Block<Thinning> runHeaderBlock;
    if (!fRawStream->GetNextBlock(runHeaderBlock))
    {
        FATAL("Cannot read CORSIKA run header");
        return eFail;
    }
    if (!runHeaderBlock.IsRunHeader())
    {
        FATAL("First block is not a run header");
        return eFail;
    }
    fRunHeader = runHeaderBlock.AsRunHeader;
    return eSuccess;
}

Status ShowerFile::FindEvent(const unsigned int eventId)
{
    if (!IsOpen()) return eEOF;
    const IdToPositionMap::const_iterator iter = fIndex.IDToPosition.find(eventId);
    if (iter == fIndex.IDToPosition.end() || iter->second >= fIndex.eventHeaders.size())
        return eFail;

    fCurrentPosition = iter->second;
    if (fIsThinned) return Read<Thinned>();
    return Read<NotThinned>();
}

size_t ShowerFile::GetNEvents()
{
    if (!fRawStream) throw IOException("Cannot request number of events from closed file");
    if (!fRawStream->IsSeekable()) throw IOException("Cannot request number of events for this file. It is not seekable.");

    if (!fFileScanned)
    {
        fIndex.Scan(*fRawStream, false);
        fFileScanned = true;
    }
    return fIndex.IDToPosition.size();
}

Status ShowerFile::ReadLongFile()
{
    //cout << "reading long file " << fLongFile << endl;
    if (!fCorsikaLongFile)
        fCorsikaLongFile.reset(new LongFile(fLongFile, GetCurrentShower().GetZenith()));

    if (fCorsikaLongFile->size() >= fCurrentPosition)
    {
        LongProfile p = fCorsikaLongFile->GetProfile(fCurrentPosition);
        fCurrentShower.fdEdX = p.fdEdX;
        fCurrentShower.fChargeProfile = p.fChargeProfile;
        fCurrentShower.fGammaProfile = p.fGammaProfile;
        fCurrentShower.fElectronProfile = p.fElectronProfile;
        fCurrentShower.fPositronProfile = p.fPositronProfile;
        fCurrentShower.fMuonProfile = p.fMuonProfile;
        fCurrentShower.fAntiMuonProfile = p.fAntiMuonProfile;
        fCurrentShower.fHadronProfile = p.fHadronProfile;
        fCurrentShower.fNucleiProfile = p.fNucleiProfile;
        fCurrentShower.fCherenkovProfile = p.fCherenkovProfile;
        fCurrentShower.fDepth_dE = p.fDepth_dE;
        fCurrentShower.fDepth = p.fDepth;

        fCurrentShower.SetGaisserHillasParams(p.fGaisserHillas);
        fCurrentShower.SetCalorimetricEnergy(p.fCalorimetricEnergy);
    }
    else
    {
        fCurrentShower.fdEdX.clear();
        fCurrentShower.fChargeProfile.clear();
        fCurrentShower.fGammaProfile.clear();
        fCurrentShower.fElectronProfile.clear();
        fCurrentShower.fPositronProfile.clear();
        fCurrentShower.fMuonProfile.clear();
        fCurrentShower.fAntiMuonProfile.clear();
        fCurrentShower.fHadronProfile.clear();
        fCurrentShower.fNucleiProfile.clear();
        fCurrentShower.fCherenkovProfile.clear();
        fCurrentShower.fDepth_dE.clear();
        fCurrentShower.fDepth.clear();

        fCurrentShower.SetCalorimetricEnergy(0);

        GaisserHillasParameter gh;
        fCurrentShower.SetGaisserHillasParams(gh);
    }
    return eSuccess;
}

template <class Thinning> Status ShowerFile::ReadLongBlocks()
{
    fRawStream->SeekTo(fIndex.longBlocks[fCurrentPosition]);

    Block<Thinning> block;
    if (!fRawStream->GetNextBlock(block) || !block.IsLongitudinal())
    {
        ostringstream err;
        err << "Cannot read CORSIKA long block at position "
            << fCurrentPosition;
        FATAL(err);
        return eFail;
    }

    if (!block.IsLongitudinal())
    {
        ostringstream err;
        err << "Block at position " << fCurrentPosition
        << " is not longitudinal";
        FATAL(err);
        return eFail;
    }
    const LongitudinalBlock& longBlock = block.AsLongitudinalBlock;

    vector<double> auxDeltaEn;
    vector<double> auxCharge;
    vector<double> auxGammas;
    vector<double> auxElectrons;
    vector<double> auxPositrons;
    vector<double> auxMuons;
    vector<double> auxAntiMuons;
    vector<double> auxHadrons;
    vector<double> auxNuclei;
    vector<double> auxCherenkov;
    vector<double> auxDepth_dE;
    vector<double> auxDepth;

    const int nBlocks = int(longBlock.fStepsAndBlocks)%100;
    //cout << int(longBlock.fStepsAndBlocks/100)<< " steps in " << nBlocks << " blocks" << endl;
    int i = 0;

    for (; i != kLongEntriesPerBlock; ++i)
    {
        if (i && !longBlock.fEntries[i].fDepth)
            break;
        auxDeltaEn.push_back(0);
        auxCharge.push_back(longBlock.fEntries[i].fCharged);
        auxGammas.push_back(longBlock.fEntries[i].fGamma);
        auxElectrons.push_back(longBlock.fEntries[i].fEminus);
        auxPositrons.push_back(longBlock.fEntries[i].fEplus);
        auxMuons.push_back(longBlock.fEntries[i].fMuMinus);
        auxAntiMuons.push_back(longBlock.fEntries[i].fMuPlus);
        auxHadrons.push_back(longBlock.fEntries[i].fNuclei);
        auxNuclei.push_back(longBlock.fEntries[i].fHadron);
        auxCherenkov.push_back(longBlock.fEntries[i].fCherenkov);
        auxDepth.push_back(longBlock.fEntries[i].fDepth);
        auxDepth_dE.push_back(longBlock.fEntries[i].fDepth);
    }

    for (int b = 1; b < nBlocks; ++b)
    {
        if (!fRawStream->GetNextBlock(block) || !block.IsLongitudinal())
        {
            ostringstream err;
            err << "Cannot read CORSIKA long block #" << b << "at position "
            << fCurrentPosition;
            FATAL(err);
            return eFail;
        }
        const LongitudinalBlock& longBlock = block.AsLongitudinalBlock;
        for (int j = 0; j != kLongEntriesPerBlock; ++j,++i)
        {
            if (j && !longBlock.fEntries[j].fDepth)
                break;
            auxDeltaEn.push_back(0);
            auxCharge.push_back(longBlock.fEntries[j].fCharged);
            auxGammas.push_back(longBlock.fEntries[j].fGamma);
            auxElectrons.push_back(longBlock.fEntries[j].fEminus);
            auxPositrons.push_back(longBlock.fEntries[j].fEplus);
            auxMuons.push_back(longBlock.fEntries[j].fMuMinus);
            auxAntiMuons.push_back(longBlock.fEntries[j].fMuPlus);
            auxHadrons.push_back(longBlock.fEntries[j].fNuclei);
            auxNuclei.push_back(longBlock.fEntries[j].fHadron);
            auxCherenkov.push_back(longBlock.fEntries[j].fCherenkov);
            auxDepth.push_back(longBlock.fEntries[j].fDepth);
            auxDepth_dE.push_back(longBlock.fEntries[j].fDepth);
        }
    }
    //cout << i << " entries read" << endl;

    fCurrentShower.fdEdX = auxDeltaEn;
    fCurrentShower.fChargeProfile = auxCharge;
    fCurrentShower.fGammaProfile = auxGammas;
    fCurrentShower.fElectronProfile = auxElectrons;
    fCurrentShower.fPositronProfile = auxPositrons;
    fCurrentShower.fMuonProfile = auxMuons;
    fCurrentShower.fAntiMuonProfile = auxAntiMuons;
    fCurrentShower.fHadronProfile = auxHadrons;
    fCurrentShower.fNucleiProfile = auxNuclei;
    fCurrentShower.fCherenkovProfile = auxCherenkov;
    fCurrentShower.fDepth_dE = auxDepth_dE;
    fCurrentShower.fDepth = auxDepth;

    // fCurrentShower.SetGaisserHillasParams(gh);
    // fCurrentShower.SetCalorimetricEnergy(energyDepositSum);

    return eSuccess;
}
<|endoftext|>


<commit_before>#pragma once

#include <cassert>
#include <type_traits>
#include <variant>

#include <athena/DNA.hpp>

/*
 * The TypedVariant system is a type-safe union implementation capable of selecting
 * a participating field type based on an enumeration constant. As an extension of
 * std::variant, the usage pattern is similar to that of std::visit. A key difference
 * with TypedVariant is the monostate is implicitly supplied as the first argument.
 * The monostate will cause the visit implementation to function as a no-op, returning
 * a specified default value.
 */

/* Example user code:

enum class ChunkType {
  Invalid = 0,
  TYP1 = SBIG('TYP1'),
  TYP2 = SBIG('TYP2'),
  TYP3 = SBIG('TYP3'),
};

struct TYP1 : TypedRecord<ChunkType::TYP1> {
  static void PrintMe() { std::cout << "TYP1" << std::endl; }
};
struct TYP2 : TypedRecord<ChunkType::TYP2> {
  static void PrintMe() { std::cout << "TYP2" << std::endl; }
};
struct TYP3 : TypedRecord<ChunkType::TYP3> {
  static void PrintMe() { std::cout << "TYP3" << std::endl; }
};

using ChunkVariant = TypedVariant<TYP1, TYP2, TYP3>;

int main(int argc, char** argv) {
  volatile ChunkType tp = ChunkType::TYP2;
  auto var = ChunkVariant::Build(tp);
  var.visit([](auto& arg) { arg.PrintMe(); });
  return 0;
}

 */

namespace hecl {

template<auto _Type>
struct TypedRecord {
  using TypedType = std::integral_constant<decltype(_Type), _Type>;
  static constexpr auto variant_type() { return _Type; }
  static constexpr bool is_monostate() { return false; }
};

template<typename _Enum>
struct TypedMonostate : TypedRecord<_Enum(0)> {
  static constexpr bool is_monostate() { return true; }
  bool operator==(const TypedMonostate& other) const { return true; }
  bool operator!=(const TypedMonostate& other) const { return false; }
};

template<typename... _Types>
class _TypedVariant : public std::variant<_Types...> {
public:
  using base = std::variant<_Types...>;
  using EnumType = typename std::variant_alternative_t<0, std::variant<_Types...>>::TypedType::value_type;

private:
  template<typename _Type, typename _Variant>
  struct _Match;

  template<typename _Type, typename _First, typename... _Rest>
  struct _Match<_Type, std::variant<_First, _Rest...>>
      : _Match<_Type, std::variant<_Rest...>> {};

  template<typename _First, typename... _Rest>
  struct _Match<typename _First::TypedType, std::variant<_First, _Rest...>>
  { using type = _First; };

public:
  template<auto _Type>
  using Match = typename _Match<std::integral_constant<decltype(_Type), _Type>, std::variant<_Types...>>::type;

private:
  template<typename _First, typename... _Rest>
  struct _Builder {
    template<typename... _Args>
    static constexpr _TypedVariant _Build(EnumType tp, _Args&&... args) {
      //static_assert(std::is_constructible_v<_First, _Args...>,
      //              "All variant types must be constructible with the same parameters.");
      if (_First::TypedType::value == tp) {
        if constexpr (std::is_constructible_v<_First, _Args...>) {
          return {_First(std::forward<_Args>(args)...)};
        } else {
          assert(false && "Variant not constructible with supplied args.");
          return {};
        }
      }
      else if constexpr (sizeof...(_Rest) > 0)
        return _Builder<_Rest...>::template _Build<_Args...>(tp, std::forward<_Args>(args)...);
      return {};
    }
    template<typename... _Args>
    static constexpr _TypedVariant _BuildSkip(EnumType tp, _Args&&... args) {
      /* This prevents selecting the monostate explicitly (so constructor arguments aren't passed) */
      if constexpr (sizeof...(_Rest) > 0)
        return _Builder<_Rest...>::template _Build<_Args...>(tp, std::forward<_Args>(args)...);
      return {};
    }
  };

public:
  template<typename... _Args>
  static constexpr _TypedVariant Build(EnumType tp, _Args&&... args) {
    return _TypedVariant::_Builder<_Types...>::template _BuildSkip<_Args...>(tp, std::forward<_Args>(args)...);
  }

  template<typename _Return, typename _Visitor>
  constexpr auto visit(_Visitor&& visitor, _Return&& def) {
    return std::visit([&](auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        return visitor(arg);
      return def;
    }, static_cast<base&>(*this));
  }

  template<typename _Visitor>
  constexpr void visit(_Visitor&& visitor) {
    std::visit([&](auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        visitor(arg);
    }, static_cast<base&>(*this));
  }

  template<typename _Return, typename _Visitor>
  constexpr auto visit(_Visitor&& visitor, _Return&& def) const {
    return std::visit([&](const auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        return visitor(arg);
      return def;
    }, static_cast<const base&>(*this));
  }

  template<typename _Visitor>
  constexpr void visit(_Visitor&& visitor) const {
    std::visit([&](const auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        visitor(arg);
    }, static_cast<const base&>(*this));
  }

  template<typename T>
  constexpr T& get() { return std::get<T>(*this); }

  template<typename T>
  constexpr const T& get() const { return std::get<T>(*this); }

  template<typename T>
  constexpr std::add_pointer_t<T> get_if() noexcept { return std::get_if<T>(this); }

  template<typename T>
  constexpr std::add_pointer_t<const T> get_if() const noexcept { return std::get_if<T>(this); }

  template<typename T>
  constexpr bool holds_alternative() const noexcept { return std::holds_alternative<T>(*this); }

  constexpr EnumType variant_type() const {
    return std::visit([](const auto& arg) {
      return arg.variant_type();
    }, static_cast<const base&>(*this));
  }

  constexpr explicit operator bool() const noexcept {
    return !std::holds_alternative<typename std::variant_alternative_t<0, std::variant<_Types...>>>(*this);
  }
};

template<typename... _Types>
using TypedVariant = _TypedVariant<TypedMonostate<typename std::variant_alternative_t
    <0, std::variant<_Types...>>::TypedType::value_type>, _Types...>;

/* DNA support below here */

template<auto _Type>
struct TypedRecordBigDNA : BigDNA, TypedRecord<_Type> {};

template<typename... _Types>
struct TypedVariantBigDNA : BigDNA, TypedVariant<_Types...> {
  AT_DECL_EXPLICIT_DNA_YAML
  template<typename... _Args>
  static constexpr TypedVariantBigDNA Build(typename TypedVariant<_Types...>::EnumType tp, _Args&&... args) {
    return TypedVariantBigDNA(TypedVariant<_Types...>::Build(tp, std::forward<_Args>(args)...));
  }
  TypedVariantBigDNA() = default;
private:
  TypedVariantBigDNA(TypedVariant<_Types...> var) : TypedVariant<_Types...>(std::move(var)) {}
};

#define AT_SPECIALIZE_TYPED_VARIANT_BIGDNA(...)                                                                        \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::Read>(                    \
      typename Read::StreamT & r) {                                                                                \
    EnumType variant_type = {};                                                                                \
    Do<athena::io::DNA<athena::Big>::Read>(athena::io::PropId("variant_type"), variant_type, r);                       \
    static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type);                                              \
    visit([&](auto& var) { var.read(r); });                                                                            \
  }                                                                                \
                                                                                \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::Write>(                   \
      typename Write::StreamT & w) {                                                                                \
    visit([&](auto& var) {                                                                                \
      using T = std::decay_t<decltype(var)>;                                                                           \
      EnumType variant_type = T::variant_type();                                                                       \
      Do<athena::io::DNA<athena::Big>::Write>(athena::io::PropId("variant_type"), variant_type, w);                    \
      var.write(w);                                                                                \
    });                                                                                \
  }                                                                                \
                                                                                \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::BinarySize>(              \
      typename BinarySize::StreamT & sz) {                                                                             \
    visit([&](auto& var) {                                                                                \
      using T = std::decay_t<decltype(var)>;                                                                           \
      EnumType variant_type = T::variant_type();                                                                       \
      Do<athena::io::DNA<athena::Big>::BinarySize>(athena::io::PropId("variant_type"), variant_type, sz);              \
      var.binarySize(sz);                                                                                \
    });                                                                                \
  }                                                                                \
  template <>                                                                                \
  inline const char* hecl::TypedVariantBigDNA<__VA_ARGS__>::DNAType() {                                                \
    return "hecl::TypedVariantBigDNA<" #__VA_ARGS__ ">";                                                               \
  }

#define AT_SPECIALIZE_TYPED_VARIANT_BIGDNA_YAML(...)                                                                   \
  AT_SPECIALIZE_TYPED_VARIANT_BIGDNA(__VA_ARGS__)                                                                      \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::ReadYaml>(                \
      typename ReadYaml::StreamT & r) {                                                                                \
    EnumType variant_type = {};                                                                                \
    Do<athena::io::DNA<athena::Big>::ReadYaml>(athena::io::PropId("variant_type"), variant_type, r);                   \
    static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type);                                              \
    visit([&](auto& var) { var.read(r); });                                                                            \
  }                                                                                \
                                                                                \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Big>::WriteYaml>(               \
      typename WriteYaml::StreamT & w) {                                                                               \
    visit([&](auto& var) {                                                                                \
      using T = std::decay_t<decltype(var)>;                                                                           \
      EnumType variant_type = T::variant_type();                                                                       \
      Do<athena::io::DNA<athena::Big>::WriteYaml>(athena::io::PropId("variant_type"), variant_type, w);                \
      var.write(w);                                                                                \
    });                                                                                \
  }

}
<commit_msg>TypedVariant: Be explicit about athena's Endian type<commit_after>#pragma once

#include <cassert>
#include <type_traits>
#include <variant>

#include <athena/DNA.hpp>

/*
 * The TypedVariant system is a type-safe union implementation capable of selecting
 * a participating field type based on an enumeration constant. As an extension of
 * std::variant, the usage pattern is similar to that of std::visit. A key difference
 * with TypedVariant is the monostate is implicitly supplied as the first argument.
 * The monostate will cause the visit implementation to function as a no-op, returning
 * a specified default value.
 */

/* Example user code:

enum class ChunkType {
  Invalid = 0,
  TYP1 = SBIG('TYP1'),
  TYP2 = SBIG('TYP2'),
  TYP3 = SBIG('TYP3'),
};

struct TYP1 : TypedRecord<ChunkType::TYP1> {
  static void PrintMe() { std::cout << "TYP1" << std::endl; }
};
struct TYP2 : TypedRecord<ChunkType::TYP2> {
  static void PrintMe() { std::cout << "TYP2" << std::endl; }
};
struct TYP3 : TypedRecord<ChunkType::TYP3> {
  static void PrintMe() { std::cout << "TYP3" << std::endl; }
};

using ChunkVariant = TypedVariant<TYP1, TYP2, TYP3>;

int main(int argc, char** argv) {
  volatile ChunkType tp = ChunkType::TYP2;
  auto var = ChunkVariant::Build(tp);
  var.visit([](auto& arg) { arg.PrintMe(); });
  return 0;
}

 */

namespace hecl {

template<auto _Type>
struct TypedRecord {
  using TypedType = std::integral_constant<decltype(_Type), _Type>;
  static constexpr auto variant_type() { return _Type; }
  static constexpr bool is_monostate() { return false; }
};

template<typename _Enum>
struct TypedMonostate : TypedRecord<_Enum(0)> {
  static constexpr bool is_monostate() { return true; }
  bool operator==(const TypedMonostate& other) const { return true; }
  bool operator!=(const TypedMonostate& other) const { return false; }
};

template<typename... _Types>
class _TypedVariant : public std::variant<_Types...> {
public:
  using base = std::variant<_Types...>;
  using EnumType = typename std::variant_alternative_t<0, std::variant<_Types...>>::TypedType::value_type;

private:
  template<typename _Type, typename _Variant>
  struct _Match;

  template<typename _Type, typename _First, typename... _Rest>
  struct _Match<_Type, std::variant<_First, _Rest...>>
      : _Match<_Type, std::variant<_Rest...>> {};

  template<typename _First, typename... _Rest>
  struct _Match<typename _First::TypedType, std::variant<_First, _Rest...>>
  { using type = _First; };

public:
  template<auto _Type>
  using Match = typename _Match<std::integral_constant<decltype(_Type), _Type>, std::variant<_Types...>>::type;

private:
  template<typename _First, typename... _Rest>
  struct _Builder {
    template<typename... _Args>
    static constexpr _TypedVariant _Build(EnumType tp, _Args&&... args) {
      //static_assert(std::is_constructible_v<_First, _Args...>,
      //              "All variant types must be constructible with the same parameters.");
      if (_First::TypedType::value == tp) {
        if constexpr (std::is_constructible_v<_First, _Args...>) {
          return {_First(std::forward<_Args>(args)...)};
        } else {
          assert(false && "Variant not constructible with supplied args.");
          return {};
        }
      }
      else if constexpr (sizeof...(_Rest) > 0)
        return _Builder<_Rest...>::template _Build<_Args...>(tp, std::forward<_Args>(args)...);
      return {};
    }
    template<typename... _Args>
    static constexpr _TypedVariant _BuildSkip(EnumType tp, _Args&&... args) {
      /* This prevents selecting the monostate explicitly (so constructor arguments aren't passed) */
      if constexpr (sizeof...(_Rest) > 0)
        return _Builder<_Rest...>::template _Build<_Args...>(tp, std::forward<_Args>(args)...);
      return {};
    }
  };

public:
  template<typename... _Args>
  static constexpr _TypedVariant Build(EnumType tp, _Args&&... args) {
    return _TypedVariant::_Builder<_Types...>::template _BuildSkip<_Args...>(tp, std::forward<_Args>(args)...);
  }

  template<typename _Return, typename _Visitor>
  constexpr auto visit(_Visitor&& visitor, _Return&& def) {
    return std::visit([&](auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        return visitor(arg);
      return def;
    }, static_cast<base&>(*this));
  }

  template<typename _Visitor>
  constexpr void visit(_Visitor&& visitor) {
    std::visit([&](auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        visitor(arg);
    }, static_cast<base&>(*this));
  }

  template<typename _Return, typename _Visitor>
  constexpr auto visit(_Visitor&& visitor, _Return&& def) const {
    return std::visit([&](const auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        return visitor(arg);
      return def;
    }, static_cast<const base&>(*this));
  }

  template<typename _Visitor>
  constexpr void visit(_Visitor&& visitor) const {
    std::visit([&](const auto& arg) {
      using T = std::decay_t<decltype(arg)>;
      if constexpr (!T::is_monostate())
        visitor(arg);
    }, static_cast<const base&>(*this));
  }

  template<typename T>
  constexpr T& get() { return std::get<T>(*this); }

  template<typename T>
  constexpr const T& get() const { return std::get<T>(*this); }

  template<typename T>
  constexpr std::add_pointer_t<T> get_if() noexcept { return std::get_if<T>(this); }

  template<typename T>
  constexpr std::add_pointer_t<const T> get_if() const noexcept { return std::get_if<T>(this); }

  template<typename T>
  constexpr bool holds_alternative() const noexcept { return std::holds_alternative<T>(*this); }

  constexpr EnumType variant_type() const {
    return std::visit([](const auto& arg) {
      return arg.variant_type();
    }, static_cast<const base&>(*this));
  }

  constexpr explicit operator bool() const noexcept {
    return !std::holds_alternative<typename std::variant_alternative_t<0, std::variant<_Types...>>>(*this);
  }
};

template<typename... _Types>
using TypedVariant = _TypedVariant<TypedMonostate<typename std::variant_alternative_t
    <0, std::variant<_Types...>>::TypedType::value_type>, _Types...>;

/* DNA support below here */

template<auto _Type>
struct TypedRecordBigDNA : BigDNA, TypedRecord<_Type> {};

template<typename... _Types>
struct TypedVariantBigDNA : BigDNA, TypedVariant<_Types...> {
  AT_DECL_EXPLICIT_DNA_YAML
  template<typename... _Args>
  static constexpr TypedVariantBigDNA Build(typename TypedVariant<_Types...>::EnumType tp, _Args&&... args) {
    return TypedVariantBigDNA(TypedVariant<_Types...>::Build(tp, std::forward<_Args>(args)...));
  }
  TypedVariantBigDNA() = default;
private:
  TypedVariantBigDNA(TypedVariant<_Types...> var) : TypedVariant<_Types...>(std::move(var)) {}
};

#define AT_SPECIALIZE_TYPED_VARIANT_BIGDNA(...)                                                                        \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Endian::Big>::Read>(            \
      typename Read::StreamT & r) {                                                                                \
    EnumType variant_type = {};                                                                                \
    Do<athena::io::DNA<athena::Endian::Big>::Read>(athena::io::PropId("variant_type"), variant_type, r);               \
    static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type);                                              \
    visit([&](auto& var) { var.read(r); });                                                                            \
  }                                                                                \
                                                                                \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Endian::Big>::Write>(           \
      typename Write::StreamT & w) {                                                                                \
    visit([&](auto& var) {                                                                                \
      using T = std::decay_t<decltype(var)>;                                                                           \
      EnumType variant_type = T::variant_type();                                                                       \
      Do<athena::io::DNA<athena::Endian::Big>::Write>(athena::io::PropId("variant_type"), variant_type, w);            \
      var.write(w);                                                                                \
    });                                                                                \
  }                                                                                \
                                                                                \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Endian::Big>::BinarySize>(      \
      typename BinarySize::StreamT & sz) {                                                                             \
    visit([&](auto& var) {                                                                                \
      using T = std::decay_t<decltype(var)>;                                                                           \
      EnumType variant_type = T::variant_type();                                                                       \
      Do<athena::io::DNA<athena::Endian::Big>::BinarySize>(athena::io::PropId("variant_type"), variant_type, sz);      \
      var.binarySize(sz);                                                                                \
    });                                                                                \
  }                                                                                \
  template <>                                                                                \
  inline const char* hecl::TypedVariantBigDNA<__VA_ARGS__>::DNAType() {                                                \
    return "hecl::TypedVariantBigDNA<" #__VA_ARGS__ ">";                                                               \
  }

#define AT_SPECIALIZE_TYPED_VARIANT_BIGDNA_YAML(...)                                                                   \
  AT_SPECIALIZE_TYPED_VARIANT_BIGDNA(__VA_ARGS__)                                                                      \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Endian::Big>::ReadYaml>(        \
      typename ReadYaml::StreamT & r) {                                                                                \
    EnumType variant_type = {};                                                                                \
    Do<athena::io::DNA<athena::Endian::Big>::ReadYaml>(athena::io::PropId("variant_type"), variant_type, r);           \
    static_cast<TypedVariant<__VA_ARGS__>&>(*this) = Build(variant_type);                                              \
    visit([&](auto& var) { var.read(r); });                                                                            \
  }                                                                                \
                                                                                \
  template <>                                                                                \
  template <>                                                                                \
  inline void hecl::TypedVariantBigDNA<__VA_ARGS__>::Enumerate<athena::io::DNA<athena::Endian::Big>::WriteYaml>(       \
      typename WriteYaml::StreamT & w) {                                                                               \
    visit([&](auto& var) {                                                                                \
      using T = std::decay_t<decltype(var)>;                                                                           \
      EnumType variant_type = T::variant_type();                                                                       \
      Do<athena::io::DNA<athena::Endian::Big>::WriteYaml>(athena::io::PropId("variant_type"), variant_type, w);        \
      var.write(w);                                                                                \
    });                                                                                \
  }

}
<|endoftext|>


<commit_before>#include "roombaRoowifi.h"
#include "croiUtil.h"

namespace Croi {

RoombaRoowifi::RoombaRoowifi(QObject *parent) :
    QObject(parent), radius_(1)
{
    roowifi_ = new RooWifi(this);
    connect(roowifi_,SIGNAL(AutoCaptureUpdated()), parent, SLOT(sensorUpdateTimerTimeout()));
}

RoombaRoowifi::~RoombaRoowifi()
{
    roowifi_->StopAutoCapture();
    roowifi_->Disconnect();
}

int RoombaRoowifi::rmb_connect(std::string ip)
{
    QString qip = QString::fromStdString(ip);
    qDebug() << "set ip to:" << qip;
    roowifi_->SetIP(qip);
    roowifi_->Connect();
    roowifi_->StartAutoCapture();
    roowifi_->SetAutoCaptureTime(500);
}

int RoombaRoowifi::disconnect()
{
    roowifi_->StopAutoCapture();
    roowifi_->Disconnect();
}

void RoombaRoowifi::safeMode()
{
    roowifi_->SafeMode();
    int Song[14];
    int SongDuration[14];

    //Pop Corn part1
    Song[0] = 82;   SongDuration[0] = RooWifi::NotesDuration::SemiQuaver;
    Song[1] = 80;   SongDuration[1] = RooWifi::NotesDuration::SemiQuaver;
    Song[2] = 82;   SongDuration[2] = RooWifi::NotesDuration::SemiQuaver;
    Song[3] = 77;   SongDuration[3] = RooWifi::NotesDuration::SemiQuaver;
    Song[4] = 73;   SongDuration[4] = RooWifi::NotesDuration::SemiQuaver;
    Song[5] = 75;   SongDuration[5] = RooWifi::NotesDuration::SemiQuaver;
    Song[6] = 70;   SongDuration[6] = RooWifi::NotesDuration::Quaver;
    Song[7] = 82;   SongDuration[7] = RooWifi::NotesDuration::SemiQuaver;
    Song[8] = 80;   SongDuration[8] = RooWifi::NotesDuration::SemiQuaver;
    Song[9] = 82;   SongDuration[9] = RooWifi::NotesDuration::SemiQuaver;
    Song[10] = 77;  SongDuration[10] = RooWifi::NotesDuration::SemiQuaver;
    Song[11] = 73;  SongDuration[11] = RooWifi::NotesDuration::SemiQuaver;
    Song[12] = 75;  SongDuration[12] = RooWifi::NotesDuration::SemiQuaver;
    Song[13] = 70;  SongDuration[13] = RooWifi::NotesDuration::Quaver;

    roowifi_->StoreSong( 1, 14, Song, SongDuration );
}

void RoombaRoowifi::fullMode()
{
    roowifi_->FullMode();
}

void RoombaRoowifi::allMotorsOn()
{
    roowifi_->AllCleaningMotors_On();
}

void RoombaRoowifi::allMotorsOff()
{
    roowifi_->AllCleaningMotors_Off();
}

void RoombaRoowifi::clean()
{
    roowifi_->Clean();
}

char RoombaRoowifi::getTemperature()
{
    return roowifi_->Sensors.Temperature;
}

unsigned short RoombaRoowifi::getChargeLevel()
{
    return roowifi_->Sensors.Charge;
}

short RoombaRoowifi::getDistance()
{
    return roowifi_->Sensors.Distance;
}

short RoombaRoowifi::getAngle()
{
    return roowifi_->Sensors.Angle;
}

int RoombaRoowifi::getRadius()
{
    return radius_;
}

void RoombaRoowifi::Drive(int Velocity, int Radius)
{
    roowifi_->Drive(Velocity, Radius);
    radius_ = Radius;
}

void RoombaRoowifi::playSong(int songNumber)
{
    roowifi_->PlaySong(songNumber);
}

void RoombaRoowifi::testSlot()
{
    qDebug() << "autocapture";
    qDebug() << "temperature" << QString::number((char) roowifi_->Sensors.Temperature );
    qDebug() << "dirt right" << QString::number(roowifi_->Sensors.DirtDetectorRight );
}

} //namespace Croi
<commit_msg>ROOWIFI: Decreaset autocapture interval<commit_after>#include "roombaRoowifi.h"
#include "croiUtil.h"

namespace Croi {

RoombaRoowifi::RoombaRoowifi(QObject *parent) :
    QObject(parent), radius_(1)
{
    roowifi_ = new RooWifi(this);
    connect(roowifi_,SIGNAL(AutoCaptureUpdated()), parent, SLOT(sensorUpdateTimerTimeout()));
}

RoombaRoowifi::~RoombaRoowifi()
{
    roowifi_->StopAutoCapture();
    roowifi_->Disconnect();
}

int RoombaRoowifi::rmb_connect(std::string ip)
{
    QString qip = QString::fromStdString(ip);
    qDebug() << "set ip to:" << qip;
    roowifi_->SetIP(qip);
    roowifi_->Connect();
    roowifi_->StartAutoCapture();
    roowifi_->SetAutoCaptureTime(100);
}

int RoombaRoowifi::disconnect()
{
    roowifi_->StopAutoCapture();
    roowifi_->Disconnect();
}

void RoombaRoowifi::safeMode()
{
    roowifi_->SafeMode();
    int Song[14];
    int SongDuration[14];

    //Pop Corn part1
    Song[0] = 82;   SongDuration[0] = RooWifi::NotesDuration::SemiQuaver;
    Song[1] = 80;   SongDuration[1] = RooWifi::NotesDuration::SemiQuaver;
    Song[2] = 82;   SongDuration[2] = RooWifi::NotesDuration::SemiQuaver;
    Song[3] = 77;   SongDuration[3] = RooWifi::NotesDuration::SemiQuaver;
    Song[4] = 73;   SongDuration[4] = RooWifi::NotesDuration::SemiQuaver;
    Song[5] = 75;   SongDuration[5] = RooWifi::NotesDuration::SemiQuaver;
    Song[6] = 70;   SongDuration[6] = RooWifi::NotesDuration::Quaver;
    Song[7] = 82;   SongDuration[7] = RooWifi::NotesDuration::SemiQuaver;
    Song[8] = 80;   SongDuration[8] = RooWifi::NotesDuration::SemiQuaver;
    Song[9] = 82;   SongDuration[9] = RooWifi::NotesDuration::SemiQuaver;
    Song[10] = 77;  SongDuration[10] = RooWifi::NotesDuration::SemiQuaver;
    Song[11] = 73;  SongDuration[11] = RooWifi::NotesDuration::SemiQuaver;
    Song[12] = 75;  SongDuration[12] = RooWifi::NotesDuration::SemiQuaver;
    Song[13] = 70;  SongDuration[13] = RooWifi::NotesDuration::Quaver;

    roowifi_->StoreSong( 1, 14, Song, SongDuration );
}

void RoombaRoowifi::fullMode()
{
    roowifi_->FullMode();
}

void RoombaRoowifi::allMotorsOn()
{
    roowifi_->AllCleaningMotors_On();
}

void RoombaRoowifi::allMotorsOff()
{
    roowifi_->AllCleaningMotors_Off();
}

void RoombaRoowifi::clean()
{
    roowifi_->Clean();
}

char RoombaRoowifi::getTemperature()
{
    return roowifi_->Sensors.Temperature;
}

unsigned short RoombaRoowifi::getChargeLevel()
{
    return roowifi_->Sensors.Charge;
}

short RoombaRoowifi::getDistance()
{
    return roowifi_->Sensors.Distance;
}

short RoombaRoowifi::getAngle()
{
    return roowifi_->Sensors.Angle;
}

int RoombaRoowifi::getRadius()
{
    return radius_;
}

void RoombaRoowifi::Drive(int Velocity, int Radius)
{
    roowifi_->Drive(Velocity, Radius);
    radius_ = Radius;
}

void RoombaRoowifi::playSong(int songNumber)
{
    roowifi_->PlaySong(songNumber);
}

void RoombaRoowifi::testSlot()
{
    qDebug() << "autocapture";
    qDebug() << "temperature" << QString::number((char) roowifi_->Sensors.Temperature );
    qDebug() << "dirt right" << QString::number(roowifi_->Sensors.DirtDetectorRight );
}

} //namespace Croi
<|endoftext|>