text: /*
   * Copyright 2014-2022 Real Logic Limited.
   *
   * 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
   *
   * https://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.
   */
  #ifndef AERON_COUNTERS_READER_H
  #define AERON_COUNTERS_READER_H
  
  #include <functional>
  
  #include "util/Exceptions.h"
  #include "util/BitUtil.h"
  #include "concurrent/AtomicBuffer.h"
  
  #include "aeronc.h"
  
  namespace aeron { namespace concurrent {
  
  /**
   * Reads the counters metadata and values buffers.
   *
   * This class is threadsafe.
   *
   * <b>Values Buffer</b>
   * <pre>
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |                        Counter Value                          |
   *  |                                                               |
   *  +---------------------------------------------------------------+
   *  |                       Registration Id                         |
   *  |                                                               |
   *  +---------------------------------------------------------------+
   *  |                          Owner Id                             |
   *  |                                                               |
   *  +---------------------------------------------------------------+
   *  |                     104 bytes of padding                     ...
   * ...                                                              |
   *  +---------------------------------------------------------------+
   *  |                   Repeats to end of buffer                   ...
   *  |                                                               |
   * ...                                                              |
   *  +---------------------------------------------------------------+
   * </pre>
   *
   * <b>Meta Data Buffer</b>
   * <pre>
   *   0                   1                   2                   3
   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *  |                        Record State                           |
   *  +---------------------------------------------------------------+
   *  |                          Type Id                              |
   *  +---------------------------------------------------------------+
   *  |                  Free-for-reuse Deadline (ms)                 |
   *  |                                                               |
   *  +---------------------------------------------------------------+
   *  |                      112 bytes for key                       ...
   * ...                                                              |
   *  +-+-------------------------------------------------------------+
   *  |R|                      Label Length                           |
   *  +-+-------------------------------------------------------------+
   *  |                  380 bytes of Label in ASCII                 ...
   * ...                                                              |
   *  +---------------------------------------------------------------+
   *  |                   Repeats to end of buffer                   ...
   *  |                                                               |
   * ...                                                              |
   *  +---------------------------------------------------------------+
   * </pre>
   */
  
  typedef std::function<void(std::int32_t, std::int32_t, const AtomicBuffer&, const std::string&)> on_counters_metadata_t;
  
  using namespace aeron::util;
  
  class CountersReader
  {
  
  public:
      inline explicit CountersReader(aeron_counters_reader_t *countersReader) :
          m_countersReader(countersReader), m_buffers{}
      {
          aeron_counters_reader_get_buffers(m_countersReader, &m_buffers);
      }
  
      template <typename F>
      void forEach(F &&onCountersMetadata) const
      {
          using handler_type = typename std::remove_reference<F>::type;
          handler_type &handler = onCountersMetadata;
          void *handler_ptr = const_cast<void *>(reinterpret_cast<const void *>(&handler));
  
          aeron_counters_reader_foreach_counter(m_countersReader, forEachCounter<handler_type>, handler_ptr);
      }
  
      inline std::int32_t maxCounterId() const
      {
          return aeron_counters_reader_max_counter_id(m_countersReader);
      }
  
      inline std::int64_t getCounterValue(std::int32_t id) const
      {
          validateCounterId(id);
          std::int64_t *counter_addr = getCounterAddress(id);
          return *counter_addr;
      }
  
      /// @cond HIDDEN_SYMBOLS
      inline std::int64_t *getCounterAddress(std::int32_t id) const
      {
          return aeron_counters_reader_addr(m_countersReader, id);
      }
      /// @endcond
  
      inline std::int64_t getCounterRegistrationId(std::int32_t id) const
      {
          validateCounterId(id);
  
          std::int64_t registrationId;
          if (aeron_counters_reader_counter_registration_id(m_countersReader, id, &registrationId) < 0)
          {
              AERON_MAP_ERRNO_TO_SOURCED_EXCEPTION_AND_THROW;
          }
  
          return registrationId;
      }
  
      inline std::int64_t getCounterOwnerId(std::int32_t id) const
      {
          validateCounterId(id);
  
          std::int64_t ownerId;
          if (aeron_counters_reader_counter_owner_id(m_countersReader, id, &ownerId) < 0)
          {
              AERON_MAP_ERRNO_TO_SOURCED_EXCEPTION_AND_THROW;
          }
  
          return ownerId;
      }
  
      inline std::int32_t getCounterState(std::int32_t id) const
      {
          std::int32_t state;
          if (aeron_counters_reader_counter_state(m_countersReader, id, &state) < 0)
          {
              throw util::IllegalArgumentException(
                  "counter id " + std::to_string(id) +
                  " out of range: maxCounterId=" + std::to_string(maxCounterId()),
                  SOURCEINFO);
          }
  
          return state;
      }
  
      inline std::int32_t getCounterTypeId(std::int32_t id) const
      {
          std::int32_t typeId;
          if (aeron_counters_reader_counter_type_id(m_countersReader, id, &typeId) < 0)
          {
              throw util::IllegalArgumentException(
                  "counter id " + std::to_string(id) +
                  " out of range: maxCounterId=" + std::to_string(maxCounterId()),
                  SOURCEINFO);
          }
  
          return typeId;
      }
  
      inline std::int64_t getFreeForReuseDeadline(std::int32_t id) const
      {
          std::int64_t deadline;
          if (aeron_counters_reader_free_for_reuse_deadline_ms(m_countersReader, id, &deadline))
          {
              throw util::IllegalArgumentException(
                  "counter id " + std::to_string(id) +
                  " out of range: maxCounterId=" + std::to_string(maxCounterId()),
                  SOURCEINFO);
          }
  
          return deadline;
      }
  
      inline std::string getCounterLabel(std::int32_t id) const
      {
          char buffer[AERON_COUNTER_MAX_LABEL_LENGTH];
          int length = aeron_counters_reader_counter_label(m_countersReader, id, buffer, sizeof(buffer));
          if (length < 0)
          {
              throw util::IllegalArgumentException(
                  "counter id " + std::to_string(id) +
                  " out of range: maxCounterId=" + std::to_string(maxCounterId()),
                  SOURCEINFO);
          }
  
          return { buffer, static_cast<std::size_t>(length) };
      }
  
      inline static util::index_t counterOffset(std::int32_t counterId)
      {
          return AERON_COUNTER_OFFSET(counterId);
      }
  
      inline static util::index_t metadataOffset(std::int32_t counterId)
      {
          return AERON_COUNTER_METADATA_OFFSET(counterId);
      }
  
      inline AtomicBuffer valuesBuffer() const
      {
          return { m_buffers.values, m_buffers.values_length };
      }
  
      inline AtomicBuffer metaDataBuffer() const
      {
          return { m_buffers.metadata, m_buffers.metadata_length };
      }
  
      static const std::int32_t NULL_COUNTER_ID = AERON_NULL_COUNTER_ID;
  
      static const std::int32_t RECORD_UNUSED = AERON_COUNTER_RECORD_UNUSED;
      static const std::int32_t RECORD_ALLOCATED = AERON_COUNTER_RECORD_ALLOCATED;
      static const std::int32_t RECORD_RECLAIMED = AERON_COUNTER_RECORD_RECLAIMED;
  
      static const std::int64_t DEFAULT_REGISTRATION_ID = AERON_COUNTER_REGISTRATION_ID_DEFAULT;
      static const std::int64_t NOT_FREE_TO_REUSE = AERON_COUNTER_NOT_FREE_TO_REUSE;
  
      static const util::index_t COUNTER_LENGTH = AERON_COUNTER_VALUE_LENGTH;
      static const util::index_t REGISTRATION_ID_OFFSET = AERON_COUNTER_REGISTRATION_ID_OFFSET;
  
      static const util::index_t METADATA_LENGTH = AERON_COUNTER_METADATA_LENGTH;
      static const util::index_t TYPE_ID_OFFSET = AERON_COUNTER_TYPE_ID_OFFSET;
      static const util::index_t FREE_FOR_REUSE_DEADLINE_OFFSET = AERON_COUNTER_FREE_FOR_REUSE_DEADLINE_OFFSET;
      static const util::index_t KEY_OFFSET = AERON_COUNTER_KEY_OFFSET;
      static const util::index_t LABEL_LENGTH_OFFSET = AERON_COUNTER_LABEL_LENGTH_OFFSET;
  
      static const std::int32_t MAX_LABEL_LENGTH = AERON_COUNTER_MAX_LABEL_LENGTH;
      static const std::int32_t MAX_KEY_LENGTH = AERON_COUNTER_MAX_KEY_LENGTH;
  
  protected:
      aeron_counters_reader_t *m_countersReader;
      aeron_counters_reader_buffers_t m_buffers;
  
      void validateCounterId(std::int32_t counterId) const
      {
          if (counterId < 0 || counterId > maxCounterId())
          {
              throw util::IllegalArgumentException(
                  "counter id " + std::to_string(counterId) +
                  " out of range: maxCounterId=" + std::to_string(maxCounterId()),
                  SOURCEINFO);
          }
      }
  
      template<typename H>
      static void forEachCounter(
          std::int64_t /* value */,
          std::int32_t id,
          std::int32_t typeId,
          const std::uint8_t *key,
          std::size_t key_length,
          const char *label,
          std::size_t label_length,
          void *clientd)
      {
          H &handler = *reinterpret_cast<H *>(clientd);
          AtomicBuffer keyBuffer = { const_cast<std::uint8_t *>(key), key_length };
          std::string labelStr = { const_cast<char *>(label), label_length };
  
          handler(id, typeId, keyBuffer, labelStr);
      }
  };
  
  }}
  
  #endif
  