Skip to content

ROOT fails to instantiate an object #18923

Open
@ktf

Description

@ktf

Check duplicate issues.

  • Checked for duplicates

Description

Using:

void foo () {
  o2::dcs::DataPointValue value;
}

results in the error below when running it with root foo.C in 6.36.00. The same works flawlessly in ROOT 6.32.06. The same macro works just fine with root foo.C+ in both versions.

   ------------------------------------------------------------------
  | Welcome to ROOT 6.36.000                       https://root.cern |
  | (c) 1995-2025, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for macosxarm64 on May 30 2025, 09:41:51                   |
  | From tags/v6-36-00-alice1@v6-36-00-alice1                        |
  | With Apple clang version 17.0.0 (clang-1700.0.13.5)              |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------


Processing foo.C...
Warning in <TInterpreter::TCling::RegisterModule>: Problems in compiling forward declarations for module G__O2DetectorsDCS: '
#line 1 "G__O2DetectorsDCS dictionary forward declarations' payload"
#pragma clang diagnostic ignored "-Wkeyword-compat"
#pragma clang diagnostic ignored "-Wignored-attributes"
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
extern int __Cling_AutoLoading_Map;
namespace o2{namespace dcs{class __attribute__((annotate("$clingAutoload$DetectorsDCS/DataPointIdentifier.h")))  DataPointIdentifier;}}
namespace std{inline namespace __1{template <class _Tp> class __attribute__((annotate("$clingAutoload$__memory/allocator.h")))  __attribute__((annotate("$clingAutoload$string")))  allocator;
}}
namespace o2{namespace dcs{struct __attribute__((annotate("$clingAutoload$DetectorsDCS/DataPointValue.h")))  DataPointValue;}}
namespace o2{namespace dcs{struct DataPointCompositeObject;}}
namespace std{inline namespace __1{template <class _CharT> struct __attribute__((annotate("$clingAutoload$__string/char_traits.h")))  __attribute__((annotate("$clingAutoload$string")))  char_traits;
}}
namespace o2{namespace dcs{class RunStatusChecker;}}
'
Error in <TInterpreter::AutoParse>: Error parsing payload code for class o2::dcs::DataPointValue with content:

#line 1 "G__O2DetectorsDCS dictionary payload"

#ifndef WITH_OPENMP
  #define WITH_OPENMP 1
#endif
#ifndef ENABLE_UPGRADES
  #define ENABLE_UPGRADES 1
#endif
#ifndef BOOST_ERROR_CODE_HEADER_ONLY
  #define BOOST_ERROR_CODE_HEADER_ONLY 1
#endif
#ifndef BOOST_ASIO_HAS_HAS_STD_CHRONO
  #define BOOST_ASIO_HAS_HAS_STD_CHRONO 1
#endif
#ifndef FAIRMQ_HAS_STD_FILESYSTEM
  #define FAIRMQ_HAS_STD_FILESYSTEM 1
#endif
#ifndef FAIRMQ_HAS_STD_PMR
  #define FAIRMQ_HAS_STD_PMR 0
#endif
#ifndef BOOST_CONTAINER_NO_LIB
  #define BOOST_CONTAINER_NO_LIB 1
#endif
#ifndef BOOST_CONTAINER_DYN_LINK
  #define BOOST_CONTAINER_DYN_LINK 1
#endif
#ifndef BOOST_PROGRAM_OPTIONS_NO_LIB
  #define BOOST_PROGRAM_OPTIONS_NO_LIB 1
#endif
#ifndef BOOST_PROGRAM_OPTIONS_DYN_LINK
  #define BOOST_PROGRAM_OPTIONS_DYN_LINK 1
#endif
#ifndef BOOST_FILESYSTEM_NO_LIB
  #define BOOST_FILESYSTEM_NO_LIB 1
#endif
#ifndef BOOST_FILESYSTEM_DYN_LINK
  #define BOOST_FILESYSTEM_DYN_LINK 1
#endif
#ifndef BOOST_ATOMIC_NO_LIB
  #define BOOST_ATOMIC_NO_LIB 1
#endif
#ifndef BOOST_ATOMIC_DYN_LINK
  #define BOOST_ATOMIC_DYN_LINK 1
#endif
#ifndef BOOST_REGEX_NO_LIB
  #define BOOST_REGEX_NO_LIB 1
#endif
#ifndef BOOST_REGEX_DYN_LINK
  #define BOOST_REGEX_DYN_LINK 1
#endif
#ifndef FMT_SHARED
  #define FMT_SHARED 1
#endif
#ifndef ROOT_SUPPORT_CLAD
  #define ROOT_SUPPORT_CLAD 1
#endif
#ifndef BOOST_IOSTREAMS_NO_LIB
  #define BOOST_IOSTREAMS_NO_LIB 1
#endif
#ifndef BOOST_IOSTREAMS_DYN_LINK
  #define BOOST_IOSTREAMS_DYN_LINK 1
#endif
#ifndef DPL_ENABLE_BACKTRACE
  #define DPL_ENABLE_BACKTRACE 1
#endif
#ifndef RANS_ENABLE_JSON
  #define RANS_ENABLE_JSON 1
#endif

#define _BACKWARD_BACKWARD_WARNING_H
// Inline headers
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/*
 * File:   DataPointCompositeObject.h
 * Author: John Lång ([email protected])
 *
 * Created on 23 September 2016, 11:28
 */
#ifndef O2_DCS_DATAPOINT_COMPOSITE_OBJECT_H
#define O2_DCS_DATAPOINT_COMPOSITE_OBJECT_H

#include <cstdint>
#include <stdexcept>
#include <ostream>
#include <string>
#include "Rtypes.h"
#include "DetectorsDCS/StringUtils.h"
#include "DetectorsDCS/DataPointIdentifier.h"
#include "DetectorsDCS/DataPointValue.h"
#include "DetectorsDCS/DeliveryType.h"

namespace o2
{
namespace dcs
{
/**
     * DataPointCompositeObject is a composition of a DataPointIdentifier and a
     * DataPointValue. It is the unit of data points that ADAPOS provides.
     *
     * @see ADAPRO::ADAPOS::DataPointIdentifier
     * @see ADAPRO::ADAPOS::DataPointValue
     */
struct DataPointCompositeObject final {
  /**
         * The DataPointIdentifier object, which occupies the first 64 bytes of
         * the DataPointCompositeObject. This object contains the immutable
         * alias and type information.
         *
         * @see ADAPRO::ADAPOS::DataPointIdentifier
         */
  const DataPointIdentifier id;

  /**
         * The DataPointValue object, which occupies the last 64 bytes of the
         * DataPointCompositeObject. This object contains the mutable parts of
         * DataPointCompositeObject. These parts are the ADAPOS flags,
         * timestamp, and the payload data.
         *
         * @see ADAPRO::ADAPOS::DataPointValue
         */
  DataPointValue data;

  /**
         * The default constructor for DataPointCompositeObject. Uses the
         * default constructors of its component, which means that their every
         * field will be filled with zeroes.
         *
        * @see ADAPRO::ADAPOS::DataPointIdentifier
        * @see ADAPRO::ADAPOS::DataPointValue
         */
  DataPointCompositeObject() noexcept : id(), data() {}

  /**
         * This constructor <em>copies</em> the given DataPointIdentifier and
         * DataPointValue into the fields <tt>id</tt> and <tt>data</tt>.
         *
         * @param id    The DPID component.
         * @param data  The DPVAL component.
         */
  DataPointCompositeObject(
    const DataPointIdentifier& id,
    const DataPointValue& data) noexcept : id(id), data(data) {}

  /**
         * Copy constructor
         */
  DataPointCompositeObject(const DataPointCompositeObject& src) noexcept : DataPointCompositeObject(src.id, src.data) {}

  DataPointCompositeObject& operator=(const DataPointCompositeObject& src) noexcept
  {
    if (&src != this) {
      memcpy(this, &src, sizeof(DataPointCompositeObject));
    }
    return *this;
  }

  /**
         * Bit-by bit equality comparison of DataPointCompositeObjects.
         *
         * @param other The right-hand operand of equality comparison.
         * @return      <tt>true</tt> or <tt>false</tt>.
         */
  inline bool operator==(const DataPointCompositeObject& other) const
    noexcept
  {
    return id == other.id && data == other.data;
  }

  /**
         * Negation of the <tt>==</tt> operator.
         *
         * @param other The right-hand side operand.
         * @return      <tt>true</tt> or <tt>false</tt>.
         */
  inline bool operator!=(const DataPointCompositeObject& other) const
    noexcept
  {
    return id != other.id || data != other.data;
  }

  /**
         * Overwrites a DataPointCompositeObject with the given <tt>id</tt> and
         * <tt>data</tt> values.
         *
         * @param id    The id value.
         * @param data  The data value.
         */
  inline void set(const DataPointIdentifier& id, DataPointValue& data) noexcept
  {
    DataPointIdentifier::FILL(this->id, (uint64_t*)&id);
    this->data = data;
  }

  /**
         * Overwrites a DataPointCompositeObject as a copy of the given 128-byte
         * segment (16 times <tt>sizeof(uint64_t)</tt>) of binary data.
         *
         * @param data Beginning of the data segment used for reading. The
         * length of the segment is assumed to be exactly 128 bytes and contain
         * a valid binary representation of a DataPointCompositeObject.
         */
  inline void set(const uint64_t* const data) noexcept
  {
    DataPointIdentifier::FILL(this->id, data);
    this->data.set(data + 8, id.get_type());
  }

  /**
         * Overwrites the state of the <tt>data</tt> field with the state of the
         * given DPVAL object, <em>except for the control flags, that will be
         * cleared out</em>.
         *
         * @param dpval A DPVAL object representing an update event to the
         * DPCOM in question.
         *
         * @see ADAPRO::ADAPOS::DataPointValue
         * @see ADAPRO::ADAPOS::DataPointValue::CONTROL_MASK
         */
  inline void update(const DataPointValue& dpval) noexcept
  {
    data.set(
      dpval.flags & ~DataPointValue::CONTROL_MASK,
      dpval.msec,
      dpval.sec,
      (uint64_t*)&dpval.payload_pt1,
      id.get_type());
  }

  /**
         * Returns a pointer to the beginning of the data part to be given to
         * DIM, which depends on the <tt>DeliveryType</tt> of this DPCOM. This
         * method is specific to ADAPOS Load Generator and ADAPOS Engine.
         *
         * @return  A <tt>(void*)</tt>.
         * @throws std::domain_error If the <tt>DeliveryType</tt> of this
         * DPCOM object was illegal (i.e. <tt>VOID</tt> or something else than
         * the enumerators of <tt>DeliveryType</tt>).
         * @see ADAPRO::ADAPOS::DeliveryType
         */
  inline void* dim_buffer() const
  {
    switch (id.get_type()) {
      case RAW_INT:
      case RAW_UINT:
      case RAW_BOOL:
      case RAW_CHAR:
      case RAW_DOUBLE:
      case RAW_TIME:
      case RAW_STRING:
      case RAW_BINARY:
      case RAW_FLOAT:
        return (void*)&data.payload_pt1;
      case DPVAL_INT:
      case DPVAL_UINT:
      case DPVAL_BOOL:
      case DPVAL_CHAR:
      case DPVAL_DOUBLE:
      case DPVAL_TIME:
      case DPVAL_STRING:
      case DPVAL_BINARY:
      case DPVAL_FLOAT:
        return (void*)&data;
      default:
      case VOID:
        throw std::domain_error("Illegal DeliveryType.");
    }
  }

  /**
         * Prints a CSV-representation of the DataPointCompositeObject into the
         * ostream. The format of the payload data depends on its type and is
         * handled automatically.
         *
         * @param os    The output stream.
         * @param dpcom The DataPointCompositeObject.
         * @return      Reference to the stream after the printing operation.
         */
  inline friend std::ostream& operator<<(std::ostream& os,
                                         const DataPointCompositeObject& dpcom) noexcept
  {
    std::string payload;
    os << dpcom.id << ";" << dpcom.data << ";";
    union Converter {
      uint64_t raw_data;
      float float_value;
      double double_value;
      uint32_t uint_value;
      int32_t int_value;
      char char_value;
      bool bool_value;
    } converter;
    converter.raw_data = dpcom.data.payload_pt1;
    switch (dpcom.id.get_type()) {
      case VOID:
        return os;
      case RAW_INT:
      case DPVAL_INT:
        return os << converter.int_value;
      case RAW_UINT:
      case DPVAL_UINT:
        return os << converter.uint_value;
      case RAW_BOOL:
      case DPVAL_BOOL:
        return os << (converter.bool_value ? "True" : "False");
      case RAW_CHAR:
      case DPVAL_CHAR:
        return os << converter.char_value;
      case RAW_FLOAT:
      case DPVAL_FLOAT:
        return os << converter.float_value;
      case RAW_DOUBLE:
      case DPVAL_DOUBLE:
        return os << converter.double_value;
      case RAW_STRING:
      case DPVAL_STRING:
        return os << std::string((char*)&dpcom.data.payload_pt1);
      case RAW_TIME:
      case DPVAL_TIME: {
        // I have no idea how to properly test the time_t backend.
        // It's probably even hardware/os/kernel specific...
#ifdef __linux__
        char buffer[17];
        std::time_t ts((dpcom.data.payload_pt1) >> 32);
        std::strftime(buffer, 32, "%FT%T", std::gmtime(&ts));
        return os << std::string(buffer) << "." << std::setw(3) << std::setfill('0') << std::to_string((dpcom.data.payload_pt1 & 0x00000000FFFF0000) >> 16)
                  << "Z";
#else
        return os << "[Timestamps not supported on this platform.]";
#endif
      }
      case RAW_BINARY:
      case DPVAL_BINARY:
      default:
        return os << o2::dcs::to_hex_little_endian(
                 (char*)&dpcom.data.payload_pt1, 56);
    }
  }

  /**
    * The destructor for DataPointCompositeObject so it is not deleted
    * and thus DataPointCompositeObject is trivially copyable
    */
  ~DataPointCompositeObject() noexcept = default;
  ClassDefNV(DataPointCompositeObject, 1);
};

/**
  * Return the value contained in the DataPointCompositeObject, if possible.
  *
  * @tparam T the expected type of the value
  *
  * @param dpcom the DataPointCompositeObject the value is extracted from
  *
  * @returns the value of the data point
  *
  * @throws if the DeliveryType of the data point is not compatible with T
  */
template <typename T>
T getValue(const DataPointCompositeObject& dpcom);

} // namespace dcs

/// Defining DataPointCompositeObject explicitly as messageable
namespace framework
{
template <typename T>
struct is_messageable;
template <>
struct is_messageable<o2::dcs::DataPointCompositeObject> : std::true_type {
};
} // namespace framework

} // namespace o2

/// Defining DataPointCompositeObject explicitly as copiable
namespace std
{
template <>
struct is_trivially_copyable<o2::dcs::DataPointCompositeObject> : std::true_type {
};
} // namespace std

#endif /* O2_DCS_DATAPOINT_COMPOSITE_OBJECT_H */
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/*
 * File:   DataPointIdentifier.h
 * Author: John Lång ([email protected])
 *
 * Created on 23 September 2016, 12:00
 */
#ifndef O2_DCS_DATAPOINT_IDENTIFIER_H
#define O2_DCS_DATAPOINT_IDENTIFIER_H

#include <cstring>
#include <string>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <functional>
#include <unordered_map>

#include "Rtypes.h"
#include "DetectorsDCS/StringUtils.h"
#include "DetectorsDCS/GenericFunctions.h"
#include "DetectorsDCS/DeliveryType.h"

namespace o2
{
namespace dcs
{
/**
     * DataPointIdentifier object is responsible for storing the alias and type
     * information of a data point.
     */
class DataPointIdentifier final
{
  const uint64_t pt1;
  const uint64_t pt2;
  const uint64_t pt3;
  const uint64_t pt4;
  const uint64_t pt5;
  const uint64_t pt6;
  const uint64_t pt7;
  const uint64_t pt8; // Contains the last 6 chars of alias and the type.

  DataPointIdentifier(
    const uint64_t pt1, const uint64_t pt2, const uint64_t pt3,
    const uint64_t pt4, const uint64_t pt5, const uint64_t pt6,
    const uint64_t pt7, const uint64_t pt8) noexcept : pt1(pt1), pt2(pt2), pt3(pt3), pt4(pt4), pt5(pt5), pt6(pt6), pt7(pt7), pt8(pt8) {}

 public:
  /**
         * The default constructor for DataPointIdentifier. Creates a DPID that
         * contains only zeroes. To fill it with alias and type, please use the
         * factory procedure <tt>fill</tt>.
         *
         * @see ADAPRO::ADAPOS::DataPointIdentifier::fill
         */
  DataPointIdentifier() noexcept : pt1(0), pt2(0), pt3(0), pt4(0), pt5(0), pt6(0), pt7(0), pt8(0)
  {
  }

  /**
         * A constructor for DataPointIdentifier. Copies the given arguments to
         * the memory segment owned by the object under construction.
         *
         * @param alias The alias of the DataPointIdentifier. Maximum length is
         * 62 characaters.
         * @param type  Type of the payload value associated with the service
         * identified by this DataPointIdentifier.
         */
  DataPointIdentifier(const std::string& alias, const DeliveryType type) noexcept : DataPointIdentifier()
  {
    strncpy((char*)this, alias.c_str(), 62);
    ((char*)&pt8)[7] = type;
  }

  /**
   * A copy constructor for DataPointIdentifier.
   */
  DataPointIdentifier(const DataPointIdentifier& src) noexcept : DataPointIdentifier(src.pt1, src.pt2, src.pt3, src.pt4, src.pt5, src.pt6, src.pt7, src.pt8) {}

  DataPointIdentifier& operator=(const DataPointIdentifier& src) noexcept
  {
    if (&src != this) {
      memcpy(this, &src, sizeof(DataPointIdentifier));
    }
    return *this;
  }

  /**
         * This stati procedure fills the given DataPointIdentifier object with
         * the given parameters.
         *
         * @param dpid  The DataPointIdentifier to be filled (i.e. overwritten).
         * @param alias Alias of the data point. This is used for identifying
         * the DIM service that publishes updates to a data point.
         * @param type  Type of the data point payload value.
         */
  static inline void FILL(
    const DataPointIdentifier& dpid,
    const std::string& alias,
    const DeliveryType type) noexcept
  {
    strncpy((char*)&dpid, alias.c_str(), 62);
    ((char*)&dpid.pt8)[7] = type;
  }

  /**
         * This static procedure copies the given 64-byte binary segment into
         * the DataPointIdentifier object.
         *
         * @param dpid  The DataPointIdentifier to be filled (i.e. overwritten).
         * @param data  Beginning of the 64-byte binary segment.
         */
  static inline void FILL(
    const DataPointIdentifier& dpid,
    const uint64_t* const data) noexcept
  {
    std::strncpy((char*)&dpid, (char*)data, 62);
    ((char*)&dpid)[63] = ((data[7] & 0xFF00000000000000) >> 56);
  }

  /**
         * The equality comparison object of DPIDs.
         *
         * @param other The other DPID object for comparison.
         * @return      <tt>true</tt> if and only if the other DPID object
         * has exactly (bit-by-bit) the same state.
         */
  inline bool operator==(const DataPointIdentifier& other) const
  {
    constexpr char mask = 0x7F;

    return (memcmp((char*)this, (char*)&other, 63) == 0) &&
           (((DeliveryType)this->get_type() & mask) == ((DeliveryType)other.get_type() & mask));
  }

  /**
         * Negation of the equality comparison.
         *
         * @param other The second operand.
         * @return      <tt>true</tt> or <tt>false</tt>.
         */
  inline bool operator!=(const DataPointIdentifier& other) const
  {
    return !(*this == other);
  }

  /**
         * Appends DataPointIdentifier object to the given stream using CSV
         * format (i.e. <tt>&lt;alias&gt; ";" &lt;type&gt;</tt>).
         */
  friend inline std::ostream& operator<<(std::ostream& os,
                                         const DataPointIdentifier& dpid) noexcept
  {
    return os << std::string((char*)&dpid) << ";" << o2::dcs::show((DeliveryType)((dpid.pt8 & 0xFF00000000000000) >> 56));
  }

  /**
         * Returns the alias of the DPID object as a C-style string (i.e.
         * null-terminated char array).
         *
         * @return The alias.
         */
  inline const char* const get_alias() const noexcept
  {
    return (char*)&pt1;
  }

  /**
         * Getter for the payload type information.
         *
         * @return a DeliveryType object.
         */
  inline DeliveryType get_type() const noexcept
  {
    return (DeliveryType)((pt8 & 0xFF00000000000000) >> 56);
  }

  /**
         * Returns a hash code calculated from the alias. <em>Note that the
         * hash code is recalculated every time when this function is called.
         * </em>
         *
         * @return An unsigned integer.
         */
  inline size_t hash_code() const noexcept
  {
    return o2::dcs::hash_code(std::string((char*)&pt1));
  }

  /**
         * The destructor for DataPointIdentifier.
         */
  ~DataPointIdentifier() noexcept = default;
  ClassDefNV(DataPointIdentifier, 1);
};

/**
     * This simple function object is used for calculating the hash code for a
     * DataPointIdentifier object in a STL container.
     *
     * @param dpid  The DataPointIdentifier object, whose hash code is to be
     * calculated.
     * @return      The calculated hash code.
     */
struct DPIDHash {
  uint64_t operator()(const o2::dcs::DataPointIdentifier& dpid)
    const
  {
    return dpid.hash_code();
  }
};
} // namespace dcs

/// Defining DataPointIdentifier explicitly as messageable
namespace framework
{
template <typename T>
struct is_messageable;
template <>
struct is_messageable<o2::dcs::DataPointIdentifier> : std::true_type {
};
} // namespace framework

} // namespace o2

// specailized std::hash
namespace std
{
template <>
struct hash<o2::dcs::DataPointIdentifier> {
  std::size_t operator()(const o2::dcs::DataPointIdentifier& dpid) const
  {
    return std::hash<uint64_t>{}(dpid.hash_code());
  }
};

template <>
struct is_trivially_copyable<o2::dcs::DataPointIdentifier> : std::true_type {
};

} // namespace std

#endif /* O2_DCS_DATAPOINT_IDENTIFIER_H */
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/*
 * File:   DataPointValue.h
 * Author: John Lång ([email protected])
 *
 * Created on 23 September 2016, 12:20
 */
#ifndef O2_DCS_DATAPOINT_VALUE
#define O2_DCS_DATAPOINT_VALUE

#include <cstring>
#include <cstdint>
#include <ctime>
#include <atomic>
#include <string>
#include <ostream>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <memory>
#include <stdexcept>
#include "Rtypes.h"
#include "DetectorsDCS/StringUtils.h"
#include "DetectorsDCS/Clock.h"
#include "DetectorsDCS/DeliveryType.h"

namespace o2
{
namespace dcs
{
/**
     * DataPointValue is the struct responsible for containing the flags,
     * timestamp, and payload value of a data point. It represents a discrete
     * update event to a data point. <em>It should be noted that the
     * constructors and setters of this struct, that take an array containing
     * binary data as parameter, don't check the length of the given array.</em>
     */
struct DataPointValue final {
  /**
         * <p>This flag is used for signaling that a DPVAL stream connection is
         * working, but there is no data to be sent.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>A</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t KEEP_ALIVE_FLAG = 0x0001;

  /**
         * <p>This flag is used for signaling the end of transmission.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>Z</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t END_FLAG = 0x0002;

  /**
         * <p>This flag is set in the ADAPOS FBI Master DPCOM object.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>M</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t FBI_FLAG = 0x0004;

  /**
         * <p>This flag is set by Producer to signal Consumer that this
         * DataPointValue object belongs to a new service, that doesn't yet have
         * its DataPointCompositeObject in the image.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>N</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t NEW_FLAG = 0x0008;

  /**
         * <p>This flag is reserved for the ADAPRO/ADAPOS Producer-Consumer
         * model. A DataPointValue is dirty if and only if it's stored in the
         * ring buffer but not been fully processed yet. This flag should always
         * be set when a DPCOM containing the DataPointValue object arrives from
         * ADAPOS Engine via TCP.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>D</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t DIRTY_FLAG = 0x0010;

  /**
         * <p>This flag is used as a part of the DPVAL mutual exclusion
         * mechanism. This flag should be set iff reader has the turn.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>U</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint64_t TURN_FLAG = 0x0020;

  /**
         * <p>This flag is used by the DPVAL mutual exclusion mechanism.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>W</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t WRITE_FLAG = 0x0040;

  /**
         * <p>This flag is used by the DPVAL mutual exclusion mechanism.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>R</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t READ_FLAG = 0x0080;

  /**
         * <p>This flag should be set if and only if there is a ring buffer
         * overflow happening. Ring buffer overflow is manifested as an
         * overwrite of a dirty DPVAL.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>O</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t OVERWRITE_FLAG = 0x0100;

  /**
         * <p>In case of buffer overflow, this flag can be used for indicating a
         * service that lost an update. <em>Not receiving this flag shouldn't be
         * taken as an indication that every update was successfully
         * transmitted.</em></p>
         * <p>If this flag is set, it will be denoted with letter <tt>V</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t VICTIM_FLAG = 0x0200;

  /**
         * <p>This flag should be set if and only if there is a DIM error
         * (namely, connection failure with the DIM service) in ADAPOS Engine
         * affecting this DataPointValue object.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>E</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t DIM_ERROR_FLAG = 0x0400;

  /**
         * <p>This flag should be set if and only if the DPID of the DPCOM
         * containing this DPVAL has incorrect or unexpected value.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>I</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t BAD_DPID_FLAG = 0x0800;

  /**
         * <p>This flag should be set if and only if the flags themselves have
         * bad or unexpedcted value.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>F</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t BAD_FLAGS_FLAG = 0x1000;

  /**
         * <p>This flag should be set if and only if the timestamp is
         * incorrect.</p>
         * <p>If this flag is set, it will be denoted with letter <tt>T</tt> in
         * the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t BAD_TIMESTAMP_FLAG = 0x2000;

  /**
         * <p>This flag should be set if and only if the payload value is bad.
         * </p><p>If this flag is set, it will be denoted with letter <tt>P</tt>
         * in the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t BAD_PAYLOAD_FLAG = 0x4000;

  /**
         * <p>This flag should be set if it a FBI contains duplicated DPCOMs
         * (i.e. DPCOMs with identical DPIDs). Also, partial FBI (with missing
         * DPCOMs) can be indicated with this flag.</p>
         * </p><p>If this flag is set, it will be denoted with letter <tt>B</tt>
         * in the CSV output generated from this DPVAL object.</p>
         */
  static constexpr uint16_t BAD_FBI_FLAG = 0x8000;

  /**
         * This mask covers the session flags: <tt>KEEP_ALIVE_FLAG</tt>,
         * <tt>END_FLAG</tt>, and <tt>FBI_MASTER_FLAG</tt>.
         *
         * @see ADAPRO::ADAPOS::DataPointValue::KEEPALIVE_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::END_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::FBI_FLAG
         */
  static constexpr uint16_t SESSION_MASK = 0x0007;

  /**
         * This mask covers the control flags: <tt>NEW_FLAG</tt>,
         * <tt>DIRTY_FLAG</tt>, <tt>TURN_FLAG</tt>, <tt>WRITE_FLAG</tt>, and
         * <tt>READ_FLAG</tt>.
         *
         * @see ADAPRO::ADAPOS::DataPointValue::NEW_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::DIRTY_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::TURN_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::WRITE_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::READ_FLAG
         */
  static constexpr uint16_t CONTROL_MASK = 0x00F8;

  /**
         * This mask covers the error flags: <tt>DIM_ERROR_FLAG</tt>,
         * <tt>OVERWRITE_FLAG</tt>, <tt>VICTIM_FLAG</tt>,
         * <tt>BAD_DPID_FLAG</tt>, <tt>BAD_FLAGS_FLAG</tt>,
         * <tt>BAD_TIMESTAMP_FLAG</tt>, <tt>BAD_PAYLOAD_FLAG</tt>, and
         * <tt>BAD_FBI_FLAG</tt>.
         *
         * @see ADAPRO::ADAPOS::DataPointValue::DIM_ERROR_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::OVERWRITE_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::VICTIM_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_DPID_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_FLAGS_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_TIMESTAMP_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_PAYLOAD_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_FBI_FLAG
         */
  static constexpr uint16_t ERROR_MASK = 0xFF00;

  /**
         * The ADAPOS flags, i.e. a bitmask of the 16 different DPVAL flags.
         *
         * @see ADAPRO::ADAPOS::DataPointValue::KEEPALIVE_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::END_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::FBI_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::NEW_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::DIRTY_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::TURN_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::WRITE_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::READ_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::DIM_ERROR_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::OVERWRITE_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_DPID_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_FLAGS_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_TIMESTAMP_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_PAYLOAD_FLAG
         * @see ADAPRO::ADAPOS::DataPointValue::BAD_FBI_FLAG
         */
  uint16_t flags = 0;

  /**
         * Milliseconds of the timestamp. This is the measured number of
         * milliseconds passed since the UNIX epoch
         * (1 January 1970, 01:00:00.000) modulo 1000. The purpose of this field
         * together with <tt>sec</tt> is to store a timestamp indicating the
         * moment of creation/modification of the DataPointValue object.
         *
         * @see ADAPRO::ADAPOS::DataPointValue::sec
         */
  uint16_t msec = 0;

  /**
         * Seconds of the timestamp. This is the measured number of seconds
         * passed since the UNIX epoch (1 January 1970, 01:00:00.000). The
         * purpose of this field together with <tt>msec</tt> is to store a
         * timestamp indicating the moment of creation/modification of the
         * DataPointValue object.
         */
  uint32_t sec = 0;

  /**
         * First part of the 56-byte binary payload value.
         */
  uint64_t payload_pt1 = 0;

  /**
         * Second part of the 56-byte binary payload value.
         */
  uint64_t payload_pt2 = 0;

  /**
         * Third part of the 56-byte binary payload value.
         */
  uint64_t payload_pt3 = 0;

  /**
         * Fourth part of the 56-byte binary payload value.
         */
  uint64_t payload_pt4 = 0;

  /**
         * Fifth part of the 56-byte binary payload value.
         */
  uint64_t payload_pt5 = 0;

  /**
         * Sixth part of the 56-byte binary payload value.
         */
  uint64_t payload_pt6 = 0;

  /**
         * Seventh part of the 56-byte binary payload value.
         */
  uint64_t payload_pt7 = 0;

  /**
         * The default constuctor of DataPointValue. Fills the object with
         * zeroes.
         */
  DataPointValue() = default;

  /**
         * The trivial copy constructor of DataPointValue.
         *
         * @param other The DataPointValue instance, whose state is to be copied
         * to the new object.
         */
  DataPointValue(const DataPointValue& other) = default;

  /**
         * Constructor for DataPointValue. <em>This constructor assumes that the
         * <tt>payload</tt> parameter points to a <tt>unit64_t</tt> array with
         * (at least) seven elements.</em> The data will be treated as binary
         * and will be written to the new DataPointValue object using
         * <tt>std::memcpy</tt>. Use of this constructor is discouraged, since
         * it might copy garbage data. Please consider using the constructor
         * with a <tt>DeliveryType</tt> parameter instead.
         *
         * @param flags         The ADAPOS flags.
         * @param milliseconds  Milliseconds of the timestamp.
         * @param seconds       Seconds of the timestamp.
         * @param payload       Pointer to a memory segment containing the
         * binary payload data. The next seven <tt>uint64_t</tt> values (i.e. 56
         * <tt>char</tt>s) will be copied to the DataPointValue object.
         * <em>payload</em> must not be <tt>nullptr</tt>. For an empty DPVAL,
         * use the default constructor.
         *
         * @deprecated Since ADAPRO 4.1.0, this constructor has become
         * deprecated. Please consider using the constructor with a
         * <tt>DeliveryType</tt> parameter instead.
         */
  [[deprecated]] DataPointValue(
    const uint16_t flags,
    const uint16_t milliseconds,
    const uint32_t seconds,
    const uint64_t* const payload) noexcept : flags(flags), msec(milliseconds), sec(seconds)
  {
    memcpy((void*)&payload_pt1, (void*)payload, 56);
  }

  /**
         * <p>Constructor for DataPointValue. Copies a data segment from the
         * array <tt>payload</tt>. Length of the copied data is determined by
         * the argument <tt>type</tt>. <em>No sanity checks on the given
         * array are performed.</em></p>
         * <p>If the given <tt>DeliveryType</t> is invalid, then the payload
         * of the new DataPointValue object will be filled with zeros.</p>
         *
         * @param flags         The ADAPOS flags.
         * @param milliseconds  Milliseconds of the timestamp.
         * @param seconds       Seconds of the timestamp.
         * @param payload       Pointer to a contiguous block of memory
         * containing the binary payload data.
         * @param type          Used for setting the payload correctly, using
         * <tt>set_payload</tt>. If this argument is <tt>VOID</tt>, then the
         * contents of the payload remain undefined.
         *
         * @throws std::domain_error If applied with an invalid DeliveryType.
         * @see ADAPRO::Data::DataPointValue::set_payload
         */
  DataPointValue(
    const uint16_t flags,
    const uint16_t milliseconds,
    const uint32_t seconds,
    const uint64_t* const payload,
    const DeliveryType type)
    : flags(flags), msec(milliseconds), sec(seconds)
  {
    set_payload(payload, type);
  }

  /**
         * Sets the given payload data to the DataPointValue. This setter avoids
         * copying garbage, because it uses the type information. However, it
         * assumes the given array to have at least the length determined by the
         * payload type.
         *
         * @param data  A binary segment containing the new payload data.
         * @param type  Type of the payload data.
         *
         * @throws std::domain_error If applied with an invalid DeliveryType.
         */
  inline void set_payload(
    const uint64_t* const data,
    const DeliveryType type)
  {
    switch (type) {
      case RAW_INT:
      case DPVAL_INT:
      case RAW_UINT:
      case DPVAL_UINT:
      case RAW_FLOAT:
      case DPVAL_FLOAT:
        this->payload_pt1 = data[0] & 0x00000000FFFFFFFF;
        break;
      case RAW_BOOL:
      case DPVAL_BOOL:
        this->payload_pt1 = (data[0] ? 1 : 0);
        break;
      case RAW_CHAR:
      case DPVAL_CHAR:
        this->payload_pt1 = data[0] & 0x00000000000000FF;
        break;
      case RAW_DOUBLE:
      case DPVAL_DOUBLE:
      case RAW_TIME:
      case DPVAL_TIME:
        this->payload_pt1 = data[0];
        break;
      case RAW_STRING:
      case DPVAL_STRING:
        std::strncpy((char*)&payload_pt1, (char*)data, 8);
        std::strncpy((char*)&payload_pt2, (char*)data + 8, 8);
        std::strncpy((char*)&payload_pt3, (char*)data + 16, 8);
        std::strncpy((char*)&payload_pt4, (char*)data + 24, 8);
        std::strncpy((char*)&payload_pt5, (char*)data + 32, 8);
        std::strncpy((char*)&payload_pt6, (char*)data + 40, 8);
        std::strncpy((char*)&payload_pt7, (char*)data + 48, 8);
        break;
      case RAW_BINARY:
      case DPVAL_BINARY:
        memcpy((void*)&payload_pt1, (void*)data, 56);
      case VOID:
        break;
      default:
        throw std::domain_error("Invalid DeliveryType.");
    }
  }

  /**
         * Returns the ADAPOS flags of the DataPointValue.
         *
         * @return ADAPOS flags.
         */
  inline uint16_t get_flags() const noexcept
  {
    return flags;
  }

  /**
         * Updates the timestamp of this DataPointValue object using system
         * clock.
         */
  inline void update_timestamp() noexcept
  {
    const uint64_t current_time(o2::dcs::epoch_time());
    msec = current_time % 1000;
    sec = current_time / 1000;
  }

  /**
         * <p>On Linux platforms, Returns a unique pointer to a string
         * containing an ISO 8601 timestamp. The value of the timestamp will be
         * calculated from the values of the fields <tt>msec</tt> and
         * <tt>sec</tt> and assuming the UTC timezone. The timestamp has the
         * following format:</p>
         * <p><tt>&lt;YYYY-MM-DD&gt; "T" &lt;HH:MM:SS.SSS&gt; "Z"</tt></p>
         *
         * @return An ISO 8601 compliant timestamp.
         */
  inline std::unique_ptr<std::string> get_timestamp() const noexcept
  {
#if defined(__linux__) || defined(__APPLE__)
    // time_t should be uint64_t (compatible) on 64-bit Linux platforms:
    char buffer[33];
    std::time_t ts((uint64_t)sec);
    std::strftime(buffer, 32, "%FT%T", std::gmtime(&ts));
    std::ostringstream oss;
    oss << std::string(buffer) << "." << std::setw(3) << std::setfill('0') << std::to_string(msec) << "Z";
    return std::make_unique<std::string>(
      std::move(oss.str()));
#else
    return std::make_unique<std::string>("Unsupported platform");
#endif
  }

  /**
         * Returns a 64-bit unsigned integer containing the timestamp value of
         * the DPVAL object.
         *
         * @return Milliseconds since the UNIX epoch (1.1.1970 01:00:00.000).
         */
  inline uint64_t get_epoch_time() const noexcept
  {
    return (((uint64_t)sec) * 1000) + msec;
  }

  /**
         * <p>The standard copy assignment operator. Performs a normal deep copy
         * operation overwriting this DataPointValue object with the other.</p>
         * <p><em>Note that this operator always copies a fixed size data
         * segment from the given DPVAL to this DPVAL regardless of the payload
         * value type. </em>Therefore, non-zero garbage data might be copied as
         * well. Using the setters with the <tt>type</tt> parameter is
         * recommended.</p>
         *
         * @param other The DataPointValue object, whose state will be copied to
         * this object.
         * @return <tt>*this</tt> after performing the copying.
         */
  DataPointValue& operator=(const DataPointValue& other) = default;

  /**
         * Bit-by bit equality comparison of DPVAL objects.
         *
         * @param other The second operand of equality comparison.
         * @return      <tt>true</tt> or <tt>false</tt>.
         */
  inline bool operator==(const DataPointValue& other) const noexcept
  {
    return memcmp((void*)this, (void*)&other, sizeof(DataPointValue)) == 0;
  }

  /**
         * Negation of the equality comparison.
         *
         * @param other The second operand.
         * @return      <tt>true</tt> or <tt>false</tt>.
         */
  inline bool operator!=(const DataPointValue& other) const noexcept
  {
    return !(*this == other);
  }

  /**
         * Sets the state of the DataPointValue. Copies a data segment from the
         * array <tt>payload</tt>. Length of the copied data is determined by
         * the argument <tt>type</tt>. <em>No sanity checks on the given array
         * are performed.</em>
         *
         * @param flags         New value for ADAPOS flags.
         * @param milliseconds  New value for milliseconds.
         * @param seconds       New value for seconds.
         * @param payload       New payload data.
         * @param type          Used for setting the payload correctly, using
         * <tt>set_payload</tt>.
         *
         * @throws std::domain_error If applied with an invalid DeliveryType.
         * @see ADAPRO::Data::DataPointValue::set_payload
         */
  inline void set(
    const uint16_t flags,
    const uint16_t milliseconds,
    const uint32_t seconds,
    const uint64_t* const payload,
    const DeliveryType type)
  {
    this->flags = flags;
    this->msec = milliseconds;
    this->sec = seconds;
    set_payload(payload, type);
  }

  /**
         * Sets the state of the DataPointValue, except for the flags. This
         * setter can be used for safely setting the state of the object without
         * interfering with the locking mechanism or invalidating the mutual
         * exclusion. This setter was added in <em>ADAPRO 2.4.0</em>.
         *
         * @param milliseconds  Milliseconds of the new timestamp.
         * @param seconds       Seconds of the new timestamp.
         * @param payload       New payload.
         * @param type          Used for setting the payload correctly, using
         * <tt>set_payload</tt>.
         *
         * @throws std::domain_error If applied with an invalid DeliveryType.
         * @see ADAPRO::Data::DataPointValue::set_payload
         */
  inline void set(
    const uint16_t milliseconds,
    const uint32_t seconds,
    const uint64_t* const payload,
    const DeliveryType type)
  {
    msec = milliseconds;
    sec = seconds;
    set_payload(payload, type);
  }

  /**
         * Sets the state of the DataPointValue. <em>No sanity checks on the
         * given array are performed.</em> The first array element is assumed to
         * contain data for the flags and the timestamp with their respective
         * sizes and order, while the rest of the array is assumed to contain
         * the payload data.
         *
         * @param data  New DPVAL contents.
         * @param type          Used for setting the payload correctly, using
         * <tt>set_payload</tt>.
         *
         * @throws std::domain_error If applied with an invalid DeliveryType.
         * @see ADAPRO::Data::DataPointValue::set_payload
         */
  inline void set(
    const uint64_t* const data,
    const DeliveryType type)
  {
    this->flags = data[0];
    this->msec = data[0] >> 16;
    this->sec = data[0] >> 32;
    set_payload(data + 1, type);
  }

  /**
         * Prints the flags and timestamp of the DataPointValue object into the
         * <tt>ostream</tt>, but not the payload data. The reason for omitting
         * the payload value is that DataPointValue lacks payload data typing
         * information, so conversion from binary to string is not meaningful.
         */
  friend inline std::ostream& operator<<(std::ostream& os,
                                         const DataPointValue& dpval) noexcept
  {
    return os << ((dpval.flags & KEEP_ALIVE_FLAG) ? "A" : "-")
              << ((dpval.flags & END_FLAG) ? "Z" : "-")
              << ((dpval.flags & FBI_FLAG) ? "M" : "-")
              << ((dpval.flags & NEW_FLAG) ? "N" : "-")
              << ((dpval.flags & DIRTY_FLAG) ? "D" : "-")
              << ((dpval.flags & TURN_FLAG) ? "U" : "-")
              << ((dpval.flags & WRITE_FLAG) ? "W" : "-")
              << ((dpval.flags & READ_FLAG) ? "R " : "- ")
              << ((dpval.flags & OVERWRITE_FLAG) ? "O" : "-")
              << ((dpval.flags & VICTIM_FLAG) ? "V" : "-")
              << ((dpval.flags & DIM_ERROR_FLAG) ? "E" : "-")
              << ((dpval.flags & BAD_DPID_FLAG) ? "I" : "-")
              << ((dpval.flags & BAD_FLAGS_FLAG) ? "F" : "-")
              << ((dpval.flags & BAD_TIMESTAMP_FLAG) ? "T" : "-")
              << ((dpval.flags & BAD_PAYLOAD_FLAG) ? "P" : "-")
              << ((dpval.flags & BAD_FBI_FLAG) ? "B;" : "-;")
              << *(dpval.get_timestamp());
  }

  /**
         * <p>Acquires the lock for writing into this DPVAL. This method is
         * based on Peterson's algorithm (with a spinlock). It can be used for
         * ensuring mutual exclusion between two threads accessing this DPVAL
         * object. <em>It is important to release the write lock by calling
         * <tt>release_write_lock()</tt> after use.</em></p>
         * <p><em>This method may or may not work due to CPU instruction
         * reordering, caching, and other optimizations.</em> Using
         * <tt>std::mutex</tt> instead is recommended.</p>
         *
         * @see ADAPRO::ADAPOS::DataPointValue::release_write_lock
         */
  inline void acquire_write_lock()
  {
    flags |= WRITE_FLAG;
    flags |= TURN_FLAG;
    while (flags & READ_FLAG && flags & TURN_FLAG) {
    }
  }

  /**
         * <p>Releases the lock for writing into this DPVAL. This function is
         * based on Peterson's algorithm (with a spinlock). It can be used for
         * ensuring mutual exclusion between two threads accessing this DPVAL
         * object.</p>
         * <p><em>This method may or may not work due to CPU instruction
         * reordering, caching, and other optimizations.</em> Using
         * <tt>std::mutex</tt> instead is recommended.</p>
         *
         * @see ADAPRO::ADAPOS::DataPointValue::acquire_write_lock
         */
  inline void release_write_lock()
  {
    flags &= ~WRITE_FLAG;
  }

  /**
         * <p>Acquires the lock for reading from this DPVAL. This function is
         * based on Peterson's algorithm (with a spinlock). It can be used for
         * ensuring mutual exclusion between two threads accessing this DPVAL
         * object. <em>It is important to release the read lock by calling
         * <tt>release_read_lock()</tt> after use.</em></p>
         * <p><em>This method may or may not work due to CPU instruction
         * reordering, caching, and other optimizations.</em> Using
         * <tt>std::mutex</tt> instead is recommended.</p>
         *
         * @see ADAPRO::ADAPOS::DataPointValue::release_read_lock
         */
  inline void acquire_read_lock()
  {
    flags |= READ_FLAG;
    flags &= ~TURN_FLAG;
    while (flags & WRITE_FLAG && !(flags & TURN_FLAG)) {
    }
  }

  /**
         * <p>Releases the lock for reading from this DPVAL. This function is
         * based on Peterson's algorithm (with a spinlock). It can be used for
         * ensuring mutual exclusion between two threads accessing this DPVAL
         * object.</p>
         * <p><em>This method may or may not work due to CPU instruction
         * reordering, caching, and other optimizations.</em> Using
         * <tt>std::mutex</tt> instead is recommended.</p>
         *
         * @see ADAPRO::ADAPOS::DataPointValue::acquire_read_lock
         */
  inline void release_read_lock()
  {
    flags &= ~READ_FLAG;
  }
  ClassDefNV(DataPointValue, 1);
};
} // namespace dcs
} // namespace o2

#endif /* O2_DCS_DATAPOINT_VALUE_H */
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#ifndef O2_RUN_STATUS_CHECKER_H
#define O2_RUN_STATUS_CHECKER_H

/// @author [email protected]

#include "DataFormatsParameters/GRPECSObject.h"
#include "DetectorsCommonDataFormats/DetID.h"

/*
  Utility class to check the status of the run with particular detectors participating
  Usage: first create an instance for the mask of detectors which must be in the run, e.g.

  RunStatusChecker runChecker{ o2::detectors::DetID::getMask("EMC,PHS") };
  const o2::parameters::GRPECSObject* myGRPECS = nullptr;

  Then, periodically check:

  myGRPECS = runChecker.check();

  The check will set the status of the run with selected detectors (can be inspected by getRunStatus() method).

  if (check.getRunStatus() == o2::dcs::RunStatusChecker::RunStatus::NONE) {
    LOGP(info, "No run with {} is ongoing or finished", o2::detectors::DetID::getNames(checker->getDetectorsMask()) );
  }
  else if (check.getRunStatus() == o2::dcs::RunStatusChecker::RunStatus::START) { // saw new run with wanted detectors
    LOGP(info, "Run {} with {} has started", checker.getFollowedRun(), o2::detectors::DetID::getNames(checker->getDetectorsMask()) );
  }
  else if (check.getRunStatus() == o2::dcs::RunStatusChecker::RunStatus::ONGOING) { // run which was already seen is still ongoing
    LOGP(info, "Run {} with {} is still ongoing", checker.getFollowedRun(), o2::detectors::DetID::getNames(checker->getDetectorsMask()) );
  }
  else if (check.getRunStatus() == o2::dcs::RunStatusChecker::RunStatus::STOP) { // run which was already seen was stopped (EOR seen)
    LOGP(info, "Run {} with {} was stopped", checker.getFollowedRun(), o2::detectors::DetID::getNames(checker->getDetectorsMask()) );
  }

  In all cases except RunStatusChecker::NONE a const non-null pointer on the GRP of the followed run will be returned.

  By default the check will be done for the current timestamp, for test purposes one can call it with arbitrary increasing timestamps
*/

namespace o2::dcs
{

class RunStatusChecker
{
 public:
  enum class RunStatus { NONE,    // check did not find onging run with current detector
                         START,   // check found a new run started
                         ONGOING, // check found ongoing run which was already checked
                         STOP     // check found that previously ongoing run was stopped
  };

  RunStatusChecker() = delete;
  RunStatusChecker(o2::detectors::DetID::mask_t detmask) : mDetMask(detmask) {}

  RunStatus getRunStatus() const { return mRunStatus; }
  int getFollowedRun() const { return mRunFollowed; }
  o2::detectors::DetID::mask_t getDetectorsMask() const { return mDetMask; }
  const o2::parameters::GRPECSObject* check(long ts = -1);

 private:
  RunStatus mRunStatus = RunStatus::NONE;
  o2::detectors::DetID::mask_t mDetMask{};
  int mRunFollowed = -1; // particular run followed, assumption is that at the given moment there might be only run with particular detector
  long mLastTimeStampChecked = -1;

  ClassDefNV(RunStatusChecker, 0);
};

} // namespace o2::dcs

#endif

#undef  _BACKWARD_BACKWARD_WARNING_H

In file included from input_line_8:1:
/Users/ktf/src/sw/BUILD/f23f0cb60b434fb9a20a3c1cb2ce0d5c862369d2/O2/foo.C:2:12: error: no type named 'DataPointValue' in namespace 'o2::dcs'
  o2::dcs::DataPointValue value;
  ~~~~~~~~~^

Reproducer

See above.

ROOT version

   ------------------------------------------------------------------
  | Welcome to ROOT 6.36.000                       https://root.cern |
  | (c) 1995-2025, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for macosxarm64 on May 30 2025, 09:41:51                   |
  | From tags/v6-36-00-alice1@v6-36-00-alice1                        |
  | With Apple clang version 17.0.0 (clang-1700.0.13.5)              |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

Installation method

aliBuild

Operating system

MacOS, Linux

Additional context

This is in the context of migrating the ALICE software to use v6-36-00 from v6-32-06. I think we had a similar issue when moving to C++20.

Metadata

Metadata

Assignees

Labels

blockerbugexperimentAffects an experiment / reported by its software & computimng experts

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions