//===-- examples/type-facilities/type-facilities.cpp ------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file examples/type-facilities/type-facilities.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2020
///
/// \brief An example showcasing various type-related support facilities.
///
//===----------------------------------------------------------------------===//

#include "rosa/config/version.h"

#include "rosa/support/log.h"
#include "rosa/support/terminal_colors.h"
#include "rosa/support/type_token.hpp"

using namespace rosa;
using namespace rosa::terminal;

int main(void) {
  LOG_INFO_STREAM << library_string() << " -- " << Color::Red
                  << "type facilities" << Color::Default << '\n';

  auto &Log = LOG_TRACE_STREAM;
  Log << "\nNumberOfBuiltinTypes: " << NumberOfBuiltinTypes
      << "\nTokenBits: " << token::TokenBits
      << "\nRepresentationBits: " << token::RepresentationBits
      << "\nMaxTokenizableListSize: " << token::MaxTokenizableListSize
      << "\n\n";

  Log << "Type number information on 'uint8_t':";
  constexpr TypeNumber TN = TypeNumberOf<uint8_t>::Value;
  Log << "\n  type number: " << PRINTABLE_TN(TN)
      << "\n  size: " << TypeForNumber<TN>::Size
      << "\n  name: " << TypeForNumber<TN>::Name << "\n\n";

  Log << "Type number information on 'std::string':";
  constexpr TypeNumber TNS = TypeNumberOf<std::string>::Value;
  Log << "\n  type number: " << PRINTABLE_TN(TNS)
      << "\n  size: " << TypeForNumber<TNS>::Size
      << "\n  name: " << TypeForNumber<TNS>::Name << "\n\n";

  Log << "Type number information of AtomConstants:";
  using Atom1 = AtomConstant<atom("atom1")>;
  using Atom2 = AtomConstant<atom("atom2")>;
  Log << "\n  std::is_same<Atom1, Atom2>::value: "
      << std::is_same<Atom1, Atom2>::value << "\n  TypeNumberOf<Atom1>::Value: "
      << PRINTABLE_TN(TypeNumberOf<Atom1>::Value)
      << "\n  TypeNumberOf<Atom2>::Value: "
      << PRINTABLE_TN(TypeNumberOf<Atom2>::Value)
      << "\n  name: " << TypeForNumber<TypeNumberOf<Atom1>::Value>::Name
      << "\n\n";

  Log << "Type token information on 'TypeList<uint8_t, uint16_t, "
         "std::string>':";
  // \c rosa::Token is generated statically.
  constexpr Token T = TypeToken<uint8_t, uint16_t, std::string>::Value;
  STATIC_ASSERT(
      (T == TypeListToken<TypeList<uint8_t, uint16_t, std::string>>::Value),
      "alias template definition is wrong");
  Token T_ = T; // We need a non-const value for dropping head later.
  // Iterate over encoded entries in \c T_.
  while (!emptyToken(T_)) {
    Log << "\n  token: " << PRINTABLE_TOKEN(T_)
        << "\n  valid: " << validToken(T_) << "\n  empty: " << emptyToken(T_)
        << "\n  length: " << static_cast<size_t>(lengthOfToken(T_))
        << "\n  head type number: " << PRINTABLE_TN(headOfToken(T_))
        << "\n  size of head: " << sizeOfHeadOfToken(T_)
        << "\n  alignment of head: " << alignmentOfHeadOfToken(T_)
        << "\n  name of head: " << nameOfHeadOfToken(T_)
        << "\n  is head uint8_t: " << isHeadOfTokenTheSameType<uint8_t>(T_)
        << "\n  is head uint16_t: " << isHeadOfTokenTheSameType<uint16_t>(T_)
        << "\n  is head std::string: "
        << isHeadOfTokenTheSameType<std::string>(T_) << "\nDropping head...";
    dropHeadOfToken(T_);
  }
  // Here when Token became empty.
  Log << "\n  token: " << PRINTABLE_TOKEN(T_) << "\n  empty: " << emptyToken(T_)
      << '\n';

  return 0;
}
