<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclarationName.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Lookup.h"

using namespace clang;

namespace cling {
namespace utils {
  Expr* Synthesize::CStyleCastPtrExpr(Sema* S, QualType Ty, uint64_t Ptr) {
    ASTContext& Ctx = S->getASTContext();
    if (!Ty->isPointerType())
      Ty = Ctx.getPointerType(Ty);
    TypeSourceInfo* TSI = Ctx.CreateTypeSourceInfo(Ty);
    const llvm::APInt Addr(8 * sizeof(void *), Ptr);

    Expr* Result = IntegerLiteral::Create(Ctx, Addr, Ctx.UnsignedLongTy,
                                          SourceLocation());
    Result = S->BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(),
                                         Result).take();
    assert(Result && "Cannot create CStyleCastPtrExpr");
    return Result;

  }

  static
  NestedNameSpecifier* GetPartiallyDesugaredNNS(const ASTContext& Ctx,
                                                NestedNameSpecifier* scope,
                            const llvm::SmallSet<const Type*, 4>& TypesToSkip){
    // Desugar the scope qualifier if needed.

    const Type* scope_type = scope->getAsType();
    if (scope_type) {
      // this is not a namespace, so we might need to desugar
      NestedNameSpecifier* outer_scope = scope->getPrefix();
      if (outer_scope) {
        outer_scope = GetPartiallyDesugaredNNS(Ctx, outer_scope, TypesToSkip);
      }

      QualType desugared =
        Transform::GetPartiallyDesugaredType(Ctx,
                                             QualType(scope_type,0),
                                             TypesToSkip,
                                             /*fullyQualify=*/false);
      // NOTE: Should check whether the type has changed or not.
      return NestedNameSpecifier::Create(Ctx,outer_scope,
                                         false /* template keyword wanted */,
                                         desugared.getTypePtr());
    }
    return scope;
  }

  static
  NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
                                                 NamespaceDecl* cl) {

     NamespaceDecl* outer
        = llvm::dyn_cast_or_null<NamespaceDecl>(cl->getDeclContext());
     if (outer && outer->getName().size()) {
        NestedNameSpecifier* outerNNS = CreateNestedNameSpecifier(Ctx,outer);
        return NestedNameSpecifier::Create(Ctx,outerNNS,
                                           cl);
     } else {
        return NestedNameSpecifier::Create(Ctx,
                                           0, /* no starting '::'*/
                                           cl);
     }
  }

  static
  NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
                                                 TagDecl *cl) {

    NamedDecl* outer = llvm::dyn_cast_or_null<NamedDecl>(cl->getDeclContext());
      if (outer && outer->getName().size()) {
        NestedNameSpecifier *outerNNS;
        if (cl->getDeclContext()->isNamespace()) {
          outerNNS = CreateNestedNameSpecifier(Ctx,
                                       llvm::dyn_cast<NamespaceDecl>(outer));
        } else {
          outerNNS = CreateNestedNameSpecifier(Ctx,
                                          llvm::dyn_cast<TagDecl>(outer));
        }
        return NestedNameSpecifier::Create(Ctx,outerNNS,
                                           false /* template keyword wanted */,
                                      Ctx.getTypeDeclType(cl).getTypePtr());
      } else {
        return NestedNameSpecifier::Create(Ctx,
                                           0, /* no starting '::'*/
                                           false /* template keyword wanted */,
                                      Ctx.getTypeDeclType(cl).getTypePtr());
     }
  }

  QualType Transform::GetPartiallyDesugaredType(const ASTContext& Ctx,
                                                QualType QT,
                               const llvm::SmallSet<const Type*, 4>& TypesToSkip,
                                                bool fullyQualify /*=true*/){
    // If there are no constains - use the standard desugaring.
    if (!TypesToSkip.size())
      return QT.getDesugaredType(Ctx);

    // In case of Int_t* we need to strip the pointer first, desugar and attach
    // the pointer once again.
    if (QT->isPointerType()) {
      // Get the qualifiers.
      Qualifiers quals = QT.getQualifiers();
      QT = GetPartiallyDesugaredType(Ctx, QT->getPointeeType(), TypesToSkip,
                                     fullyQualify);
      QT = Ctx.getPointerType(QT);
      // Add back the qualifiers.
      QT = Ctx.getQualifiedType(QT, quals);
    }

    // In case of Int_t& we need to strip the pointer first, desugar and attach
    // the pointer once again.
    if (QT->isReferenceType()) {
      // Get the qualifiers.
      bool isLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
      Qualifiers quals = QT.getQualifiers();
      QT = GetPartiallyDesugaredType(Ctx, QT->getPointeeType(), TypesToSkip,
                                     fullyQualify);
      // Add the r- or l- value reference type back to the desugared one
      if (isLValueRefTy)
        QT = Ctx.getLValueReferenceType(QT);
      else
        QT = Ctx.getRValueReferenceType(QT);
      // Add back the qualifiers.
      QT = Ctx.getQualifiedType(QT, quals);
    }

    while(isa<TypedefType>(QT.getTypePtr())) {
      if (!TypesToSkip.count(QT.getTypePtr()))
        QT = QT.getSingleStepDesugaredType(Ctx);
      else
        return QT;
    }
    NestedNameSpecifier* prefix = 0;
    const ElaboratedType* etype
      = llvm::dyn_cast<ElaboratedType>(QT.getTypePtr());
    if (etype) {
      // We have to also desugar the prefix.

      prefix = GetPartiallyDesugaredNNS(Ctx, etype->getQualifier(), TypesToSkip);
      QT = QualType(etype->getNamedType().getTypePtr(),QT.getLocalFastQualifiers());
    } else if (fullyQualify) {
      // Let's check whether this type should have been an elaborated type.
      // in which case we want to add it ... but we can't really preserve
      // the typedef in this case ...
      CXXRecordDecl* cl = QT->getAsCXXRecordDecl();
      if (cl) {
         NamedDecl* outer
            = llvm::dyn_cast_or_null<NamedDecl>(cl->getDeclContext());
         if (outer && outer->getName ().size()) {
            if (cl->getDeclContext()->isNamespace()) {
               prefix = CreateNestedNameSpecifier(Ctx,
                                          llvm::dyn_cast<NamespaceDecl>(outer));
            } else {
               prefix = CreateNestedNameSpecifier(Ctx,
                                          llvm::dyn_cast<TagDecl>(outer));
            }
         }
      }
    }

    // In case of template specializations iterate over the arguments and
    // desugar them as well.
    if(const TemplateSpecializationType* TST
       = dyn_cast<const TemplateSpecializationType>(QT.getTypePtr())) {

      bool mightHaveChanged = false;
      llvm::SmallVector<TemplateArgument, 4> desArgs;
      for(TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
          I != E; ++I) {
        QualType SubTy = I->getAsType();

        if (SubTy.isNull()) {
           desArgs.push_back(*I);
           continue;
        }

        // Check if the type needs more desugaring and recurse.
        if (isa<TypedefType>(SubTy)
            || isa<TemplateSpecializationType>(SubTy)
            || fullyQualify) {
          mightHaveChanged = true;
          desArgs.push_back(TemplateArgument(GetPartiallyDesugaredType(Ctx,
                                                                       SubTy,
                                                                     TypesToSkip,
                                                                 fullyQualify)));
        } else
          desArgs.push_back(*I);
      }

      // If desugaring happened allocate new type in the AST.
      if (mightHaveChanged) {
        QT = Ctx.getTemplateSpecializationType(TST->getTemplateName(),
                                              desArgs.data(),
                                              desArgs.size(),
                                              TST->getCanonicalTypeInternal());
      }
    }
    if (prefix) {
       QT = Ctx.getElaboratedType(ETK_None,prefix,QT);
    }
    return QT;
  }

  NamespaceDecl* Lookup::Namespace(Sema* S, const char* Name,
                                   DeclContext* Within) {
    DeclarationName DName = &S->Context.Idents.get(Name);
    LookupResult R(*S, DName, SourceLocation(),
                   Sema::LookupNestedNameSpecifierName);
    if (!Within)
      S->LookupName(R, S->TUScope);
    else
      S->LookupQualifiedName(R, Within);

    if (R.empty())
      return 0;

    R.resolveKind();

    return dyn_cast<NamespaceDecl>(R.getFoundDecl());
  }

  NamedDecl* Lookup::Named(Sema* S, const char* Name, DeclContext* Within) {
    DeclarationName DName = &S->Context.Idents.get(Name);

    LookupResult R(*S, DName, SourceLocation(), Sema::LookupOrdinaryName,
                   Sema::ForRedeclaration);
    if (!Within)
      S->LookupName(R, S->TUScope);
    else
      S->LookupQualifiedName(R, Within);

    if (R.empty())
      return 0;

    R.resolveKind();

    return R.getFoundDecl();

  }
} // end namespace utils
} // end namespace cling
<commit_msg>Do not use standard desugaring if we need to have the full qualification<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclarationName.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Lookup.h"

using namespace clang;

namespace cling {
namespace utils {
  Expr* Synthesize::CStyleCastPtrExpr(Sema* S, QualType Ty, uint64_t Ptr) {
    ASTContext& Ctx = S->getASTContext();
    if (!Ty->isPointerType())
      Ty = Ctx.getPointerType(Ty);
    TypeSourceInfo* TSI = Ctx.CreateTypeSourceInfo(Ty);
    const llvm::APInt Addr(8 * sizeof(void *), Ptr);

    Expr* Result = IntegerLiteral::Create(Ctx, Addr, Ctx.UnsignedLongTy,
                                          SourceLocation());
    Result = S->BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(),
                                         Result).take();
    assert(Result && "Cannot create CStyleCastPtrExpr");
    return Result;

  }

  static
  NestedNameSpecifier* GetPartiallyDesugaredNNS(const ASTContext& Ctx,
                                                NestedNameSpecifier* scope,
                            const llvm::SmallSet<const Type*, 4>& TypesToSkip){
    // Desugar the scope qualifier if needed.

    const Type* scope_type = scope->getAsType();
    if (scope_type) {
      // this is not a namespace, so we might need to desugar
      NestedNameSpecifier* outer_scope = scope->getPrefix();
      if (outer_scope) {
        outer_scope = GetPartiallyDesugaredNNS(Ctx, outer_scope, TypesToSkip);
      }

      QualType desugared =
        Transform::GetPartiallyDesugaredType(Ctx,
                                             QualType(scope_type,0),
                                             TypesToSkip,
                                             /*fullyQualify=*/false);
      // NOTE: Should check whether the type has changed or not.
      return NestedNameSpecifier::Create(Ctx,outer_scope,
                                         false /* template keyword wanted */,
                                         desugared.getTypePtr());
    }
    return scope;
  }

  static
  NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
                                                 NamespaceDecl* cl) {

     NamespaceDecl* outer
        = llvm::dyn_cast_or_null<NamespaceDecl>(cl->getDeclContext());
     if (outer && outer->getName().size()) {
        NestedNameSpecifier* outerNNS = CreateNestedNameSpecifier(Ctx,outer);
        return NestedNameSpecifier::Create(Ctx,outerNNS,
                                           cl);
     } else {
        return NestedNameSpecifier::Create(Ctx,
                                           0, /* no starting '::'*/
                                           cl);
     }
  }

  static
  NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
                                                 TagDecl *cl) {

    NamedDecl* outer = llvm::dyn_cast_or_null<NamedDecl>(cl->getDeclContext());
      if (outer && outer->getName().size()) {
        NestedNameSpecifier *outerNNS;
        if (cl->getDeclContext()->isNamespace()) {
          outerNNS = CreateNestedNameSpecifier(Ctx,
                                       llvm::dyn_cast<NamespaceDecl>(outer));
        } else {
          outerNNS = CreateNestedNameSpecifier(Ctx,
                                          llvm::dyn_cast<TagDecl>(outer));
        }
        return NestedNameSpecifier::Create(Ctx,outerNNS,
                                           false /* template keyword wanted */,
                                      Ctx.getTypeDeclType(cl).getTypePtr());
      } else {
        return NestedNameSpecifier::Create(Ctx,
                                           0, /* no starting '::'*/
                                           false /* template keyword wanted */,
                                      Ctx.getTypeDeclType(cl).getTypePtr());
     }
  }

  QualType Transform::GetPartiallyDesugaredType(const ASTContext& Ctx,
                                                QualType QT,
                               const llvm::SmallSet<const Type*, 4>& TypesToSkip,
                                                bool fullyQualify /*=true*/){
    // If there are no constains - use the standard desugaring.
    if (!TypesToSkip.size() && !fullyQualify)
      return QT.getDesugaredType(Ctx);

    // In case of Int_t* we need to strip the pointer first, desugar and attach
    // the pointer once again.
    if (QT->isPointerType()) {
      // Get the qualifiers.
      Qualifiers quals = QT.getQualifiers();
      QT = GetPartiallyDesugaredType(Ctx, QT->getPointeeType(), TypesToSkip,
                                     fullyQualify);
      QT = Ctx.getPointerType(QT);
      // Add back the qualifiers.
      QT = Ctx.getQualifiedType(QT, quals);
    }

    // In case of Int_t& we need to strip the pointer first, desugar and attach
    // the pointer once again.
    if (QT->isReferenceType()) {
      // Get the qualifiers.
      bool isLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
      Qualifiers quals = QT.getQualifiers();
      QT = GetPartiallyDesugaredType(Ctx, QT->getPointeeType(), TypesToSkip,
                                     fullyQualify);
      // Add the r- or l- value reference type back to the desugared one
      if (isLValueRefTy)
        QT = Ctx.getLValueReferenceType(QT);
      else
        QT = Ctx.getRValueReferenceType(QT);
      // Add back the qualifiers.
      QT = Ctx.getQualifiedType(QT, quals);
    }

    while(isa<TypedefType>(QT.getTypePtr())) {
      if (!TypesToSkip.count(QT.getTypePtr()))
        QT = QT.getSingleStepDesugaredType(Ctx);
      else
        return QT;
    }
    NestedNameSpecifier* prefix = 0;
    const ElaboratedType* etype
      = llvm::dyn_cast<ElaboratedType>(QT.getTypePtr());
    if (etype) {
      // We have to also desugar the prefix.

      prefix = GetPartiallyDesugaredNNS(Ctx, etype->getQualifier(), TypesToSkip);
      QT = QualType(etype->getNamedType().getTypePtr(),QT.getLocalFastQualifiers());
    } else if (fullyQualify) {
      // Let's check whether this type should have been an elaborated type.
      // in which case we want to add it ... but we can't really preserve
      // the typedef in this case ...
      CXXRecordDecl* cl = QT->getAsCXXRecordDecl();
      if (cl) {
         NamedDecl* outer
            = llvm::dyn_cast_or_null<NamedDecl>(cl->getDeclContext());
         if (outer && outer->getName ().size()) {
            if (cl->getDeclContext()->isNamespace()) {
               prefix = CreateNestedNameSpecifier(Ctx,
                                          llvm::dyn_cast<NamespaceDecl>(outer));
            } else {
               prefix = CreateNestedNameSpecifier(Ctx,
                                          llvm::dyn_cast<TagDecl>(outer));
            }
         }
      }
    }

    // In case of template specializations iterate over the arguments and
    // desugar them as well.
    if(const TemplateSpecializationType* TST
       = dyn_cast<const TemplateSpecializationType>(QT.getTypePtr())) {

      bool mightHaveChanged = false;
      llvm::SmallVector<TemplateArgument, 4> desArgs;
      for(TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
          I != E; ++I) {
        QualType SubTy = I->getAsType();

        if (SubTy.isNull()) {
           desArgs.push_back(*I);
           continue;
        }

        // Check if the type needs more desugaring and recurse.
        if (isa<TypedefType>(SubTy)
            || isa<TemplateSpecializationType>(SubTy)
            || fullyQualify) {
          mightHaveChanged = true;
          desArgs.push_back(TemplateArgument(GetPartiallyDesugaredType(Ctx,
                                                                       SubTy,
                                                                     TypesToSkip,
                                                                 fullyQualify)));
        } else
          desArgs.push_back(*I);
      }

      // If desugaring happened allocate new type in the AST.
      if (mightHaveChanged) {
        // This lose any qualifiers in the original QT (intentional for now)
        QT = Ctx.getTemplateSpecializationType(TST->getTemplateName(),
                                               desArgs.data(),
                                               desArgs.size(),
                                               TST->getCanonicalTypeInternal());
      }
    }
    if (prefix) {
       QT = Ctx.getElaboratedType(ETK_None,prefix,QT);
    }
    return QT;
  }

  NamespaceDecl* Lookup::Namespace(Sema* S, const char* Name,
                                   DeclContext* Within) {
    DeclarationName DName = &S->Context.Idents.get(Name);
    LookupResult R(*S, DName, SourceLocation(),
                   Sema::LookupNestedNameSpecifierName);
    if (!Within)
      S->LookupName(R, S->TUScope);
    else
      S->LookupQualifiedName(R, Within);

    if (R.empty())
      return 0;

    R.resolveKind();

    return dyn_cast<NamespaceDecl>(R.getFoundDecl());
  }

  NamedDecl* Lookup::Named(Sema* S, const char* Name, DeclContext* Within) {
    DeclarationName DName = &S->Context.Idents.get(Name);

    LookupResult R(*S, DName, SourceLocation(), Sema::LookupOrdinaryName,
                   Sema::ForRedeclaration);
    if (!Within)
      S->LookupName(R, S->TUScope);
    else
      S->LookupQualifiedName(R, Within);

    if (R.empty())
      return 0;

    R.resolveKind();

    return R.getFoundDecl();

  }
} // end namespace utils
} // end namespace cling
<|endoftext|>


<commit_before>/*
 Basic Server code for CMPT 276, Spring 2016.
 */

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "TableCache.h"
#include "config.h"
#include "make_unique.h"

#include "azure_keys.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34568";

const string create_table {"CreateTable"};
const string delete_table {"DeleteTable"};
const string update_entity {"UpdateEntity"};
const string delete_entity {"DeleteEntity"};

/*
  Cache of opened tables
 */
TableCache table_cache {storage_connection_string};

/*
  Convert properties represented in Azure Storage type
  to prop_vals_t type.
 */
prop_vals_t get_properties (const table_entity::properties_type& properties, prop_vals_t values = prop_vals_t {}) {
  for (const auto v : properties) {
    if (v.second.property_type() == edm_type::string) {
      values.push_back(make_pair(v.first, value::string(v.second.string_value())));
    }
    else if (v.second.property_type() == edm_type::datetime) {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
    else if(v.second.property_type() == edm_type::int32) {
      values.push_back(make_pair(v.first, value::number(v.second.int32_value())));
    }
    else if(v.second.property_type() == edm_type::int64) {
      values.push_back(make_pair(v.first, value::number(v.second.int64_value())));
    }
    else if(v.second.property_type() == edm_type::double_floating_point) {
      values.push_back(make_pair(v.first, value::number(v.second.double_value())));
    }
    else if(v.second.property_type() == edm_type::boolean) {
      values.push_back(make_pair(v.first, value::boolean(v.second.boolean_value())));
    }
    else {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
  }
  return values;
}

/*
  Given an HTTP message with a JSON body, return the JSON
  body as an unordered map of strings to strings.

  Note that all types of JSON values are returned as strings.
  Use C++ conversion utilities to convert to numbers or dates
  as necessary.
 */
unordered_map<string,string> get_json_body(http_request message) {
  unordered_map<string,string> results {};
  const http_headers& headers {message.headers()};
  auto content_type (headers.find("Content-Type"));
  if (content_type == headers.end() ||
      content_type->second != "application/json")
    return results;

  value json{};
  message.extract_json(true)
    .then([&json](value v) -> bool
	  {
            json = v;
	    return true;
	  })
    .wait();

  if (json.is_object()) {
    for (const auto& v : json.as_object()) {
      if (v.second.is_string()) {
	results[v.first] = v.second.as_string();
      }
      else {
	results[v.first] = v.second.serialize();
      }
    }
  }
  return results;
}

/*
  Top-level routine for processing all HTTP GET requests.

  GET is the only request that has no command. All
  operands specify the value(s) to be retrieved.
 */
void handle_get(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** GET " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least a table name
  if (paths.size() < 1) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[0])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  // GET all entries in table
  if (paths.size() == 1) {
    table_query query {};
    table_query_iterator end;
    table_query_iterator it = table.execute_query(query);
    vector<value> key_vec;
    while (it != end) {
      cout << "Key: " << it->partition_key() << " / " << it->row_key() << endl;
      prop_vals_t keys {
	make_pair("Partition",value::string(it->partition_key())),
	make_pair("Row", value::string(it->row_key()))};
      keys = get_properties(it->properties(), keys);
      key_vec.push_back(value::object(keys));
      ++it;
    }
    message.reply(status_codes::OK, value::array(key_vec));
    return;
  }

  // GET specific entry: Partition == paths[1], Row == paths[2]
  table_operation retrieve_operation {table_operation::retrieve_entity(paths[1], paths[2])};
  table_result retrieve_result {table.execute(retrieve_operation)};
  cout << "HTTP code: " << retrieve_result.http_status_code() << endl;
  if (retrieve_result.http_status_code() == status_codes::NotFound) {
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {retrieve_result.entity()};
  table_entity::properties_type properties {entity.properties()};

  // If the entity has any properties, return them as JSON
  prop_vals_t values (get_properties(properties));
  if (values.size() > 0)
    message.reply(status_codes::OK, value::object(values));
  else
    message.reply(status_codes::OK);
}

/*
  Top-level routine for processing all HTTP POST requests.
 */
void handle_post(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and a table name
  if (paths.size() < 2) {
    message.reply(status_codes::BadRequest);
    return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Create table (idempotent if table exists)
  if (paths[0] == create_table) {
    cout << "Create " << table_name << endl;
    bool created {table.create_if_not_exists()};
    cout << "Administrative table URI " << table.uri().primary_uri().to_string() << endl;
    if (created)
      message.reply(status_codes::Created);
    else
      message.reply(status_codes::Accepted);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP PUT requests.
 */
void handle_put(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** PUT " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation, table name, partition, and row
  if (paths.size() < 4) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[1])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {paths[2], paths[3]};

  // Update entity
  if (paths[0] == update_entity) {
    cout << "Update " << entity.partition_key() << " / " << entity.row_key() << endl;
    table_entity::properties_type& properties = entity.properties();
    for (const auto v : get_json_body(message)) {
      properties[v.first] = entity_property {v.second};
    }

    table_operation operation {table_operation::insert_or_merge_entity(entity)};
    table_result op_result {table.execute(operation)};

    message.reply(status_codes::OK);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP DELETE requests.
 */
void handle_delete(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** DELETE " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and table name
  if (paths.size() < 2) {
	message.reply(status_codes::BadRequest);
	return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Delete table
  if (paths[0] == delete_table) {
    cout << "Delete " << table_name << endl;
    if ( ! table.exists()) {
      message.reply(status_codes::NotFound);
    }
    table.delete_table();
    table_cache.delete_entry(table_name);
    message.reply(status_codes::OK);
  }
  // Delete entity
  else if (paths[0] == delete_entity) {
    // For delete entity, also need partition and row
    if (paths.size() < 4) {
	message.reply(status_codes::BadRequest);
	return;
    }
    table_entity entity {paths[2], paths[3]};
    cout << "Delete " << entity.partition_key() << " / " << entity.row_key()<< endl;

    table_operation operation {table_operation::delete_entity(entity)};
    table_result op_result {table.execute(operation)};

    int code {op_result.http_status_code()};
    if (code == status_codes::OK ||
	code == status_codes::NoContent)
      message.reply(status_codes::OK);
    else
      message.reply(code);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Main server routine

  Install handlers for the HTTP requests and open the listener,
  which processes each request asynchronously.

  Wait for a carriage return, then shut the server down.
 */
int main (int argc, char const * argv[]) {
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get);
  listener.support(methods::POST, &handle_post);
  listener.support(methods::PUT, &handle_put);
  listener.support(methods::DEL, &handle_delete);
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<commit_msg>get partition through specific enrties<commit_after>/*
 Basic Server code for CMPT 276, Spring 2016.
 */

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <string>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "TableCache.h"
#include "config.h"
#include "make_unique.h"

#include "azure_keys.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34568";

const string create_table {"CreateTable"};
const string delete_table {"DeleteTable"};
const string update_entity {"UpdateEntity"};
const string delete_entity {"DeleteEntity"};

/*
  Cache of opened tables
 */
TableCache table_cache {storage_connection_string};

/*
  Convert properties represented in Azure Storage type
  to prop_vals_t type.
 */
prop_vals_t get_properties (const table_entity::properties_type& properties, prop_vals_t values = prop_vals_t {}) {
  for (const auto v : properties) {
    if (v.second.property_type() == edm_type::string) {
      values.push_back(make_pair(v.first, value::string(v.second.string_value())));
    }
    else if (v.second.property_type() == edm_type::datetime) {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
    else if(v.second.property_type() == edm_type::int32) {
      values.push_back(make_pair(v.first, value::number(v.second.int32_value())));
    }
    else if(v.second.property_type() == edm_type::int64) {
      values.push_back(make_pair(v.first, value::number(v.second.int64_value())));
    }
    else if(v.second.property_type() == edm_type::double_floating_point) {
      values.push_back(make_pair(v.first, value::number(v.second.double_value())));
    }
    else if(v.second.property_type() == edm_type::boolean) {
      values.push_back(make_pair(v.first, value::boolean(v.second.boolean_value())));
    }
    else {
      values.push_back(make_pair(v.first, value::string(v.second.str())));
    }
  }
  return values;
}

/*
  Given an HTTP message with a JSON body, return the JSON
  body as an unordered map of strings to strings.

  Note that all types of JSON values are returned as strings.
  Use C++ conversion utilities to convert to numbers or dates
  as necessary.
 */
unordered_map<string,string> get_json_body(http_request message) {
  unordered_map<string,string> results {};
  const http_headers& headers {message.headers()};
  auto content_type (headers.find("Content-Type"));
  if (content_type == headers.end() ||
      content_type->second != "application/json")
    return results;

  value json{};
  message.extract_json(true)
    .then([&json](value v) -> bool
	  {
            json = v;
	    return true;
	  })
    .wait();

  if (json.is_object()) {
    for (const auto& v : json.as_object()) {
      if (v.second.is_string()) {
	results[v.first] = v.second.as_string();
      }
      else {
	results[v.first] = v.second.serialize();
      }
    }
  }
  return results;
}

/*
  Top-level routine for processing all HTTP GET requests.

  GET is the only request that has no command. All
  operands specify the value(s) to be retrieved.
 */
void handle_get(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** GET " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least a table name
  if (paths.size() < 1) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[0])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  // GET all entries in table
  if (paths.size() == 1) {
    table_query query {};
    table_query_iterator end;
    table_query_iterator it = table.execute_query(query);
    vector<value> key_vec;
    while (it != end) {
      cout << "Key: " << it->partition_key() << " / " << it->row_key() << endl;
      prop_vals_t keys {
	make_pair("Partition",value::string(it->partition_key())),
	make_pair("Row", value::string(it->row_key()))};
      keys = get_properties(it->properties(), keys);
      key_vec.push_back(value::object(keys));
      ++it;
    }
    message.reply(status_codes::OK, value::array(key_vec));
    return;
  }

  // GET specific entry: Partition == paths[1], Row == paths[2]
  table_operation retrieve_operation {table_operation::retrieve_entity(paths[1], paths[2])};
  table_result retrieve_result {table.execute(retrieve_operation)};
  cout << "HTTP code: " << retrieve_result.http_status_code() << endl;
  if (retrieve_result.http_status_code() == status_codes::NotFound) {   // if the table does not exist
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {retrieve_result.entity()};
  table_entity::properties_type properties {entity.properties()};

  unordered_map<string,string> json_body {get_json_body (message)};

  if (json_body.size () > 0) { // There was a body
    std::vector<string> nameList;
    for (const auto v : json_body) { // for every pair in json_body (unordered map)
    // v is a pair<string,string> representing a property in the JSON object
      if(v.second == "*"){
        nameList.push_back(v.first);
      }
    }
    // Do other things for the case where the message had a body
    // creates query
    table_query query {};
    table_query_iterator end;

    /*
    access_condition exisiting = azure::storage::access_condition();
    for(int i = 0 ; i < nameList.size() ; i++){
      // Construct the query operation for all entities that fit the name

      static const utility::string_t addition = azure::storage::table_query::generate_filter_condition ( "RowKey",
        azure::storage::query_comparison_operator::equal, , nameList[i]);

      query.set_filter_string(query.combine_filter_conditions (exisiting,
        static const utility::string_t azure::storage::query_logical_operator::op_and, addition));
    }*/

    // Execute Query
      table_query_iterator it = table.execute_query(query);
      vector<value> key_vec;
      while (it != end) {
        cout << "Key: " << it->partition_key() << endl;
        prop_vals_t keys {
      make_pair("Partition",value::string(it->partition_key()))};
        keys = get_properties(it->properties(), keys);
        key_vec.push_back(value::object(keys));
        ++it;
      }
  }

  // If the entity has any properties, return them as JSON
  prop_vals_t values (get_properties(properties));
  if (values.size() > 0)
    message.reply(status_codes::OK, value::object(values));
  else
    message.reply(status_codes::OK);
}

/*
  Top-level routine for processing all HTTP POST requests.
 */
void handle_post(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and a table name
  if (paths.size() < 2) {
    message.reply(status_codes::BadRequest);
    return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Create table (idempotent if table exists)
  if (paths[0] == create_table) {
    cout << "Create " << table_name << endl;
    bool created {table.create_if_not_exists()};
    cout << "Administrative table URI " << table.uri().primary_uri().to_string() << endl;
    if (created)
      message.reply(status_codes::Created);
    else
      message.reply(status_codes::Accepted);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP PUT requests.
 */
void handle_put(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** PUT " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation, table name, partition, and row
  if (paths.size() < 4) {
    message.reply(status_codes::BadRequest);
    return;
  }

  cloud_table table {table_cache.lookup_table(paths[1])};
  if ( ! table.exists()) {
    message.reply(status_codes::NotFound);
    return;
  }

  table_entity entity {paths[2], paths[3]}; // partition and row

  // Update entity
  if (paths[0] == update_entity) {
    cout << "Update " << entity.partition_key() << " / " << entity.row_key() << endl;
    table_entity::properties_type& properties = entity.properties();
    for (const auto v : get_json_body(message)) {
      properties[v.first] = entity_property {v.second};
    }

    table_operation operation {table_operation::insert_or_merge_entity(entity)};
    table_result op_result {table.execute(operation)};

    message.reply(status_codes::OK);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Top-level routine for processing all HTTP DELETE requests.
 */
void handle_delete(http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** DELETE " << path << endl;
  auto paths = uri::split_path(path);
  // Need at least an operation and table name
  if (paths.size() < 2) {
	message.reply(status_codes::BadRequest);
	return;
  }

  string table_name {paths[1]};
  cloud_table table {table_cache.lookup_table(table_name)};

  // Delete table
  if (paths[0] == delete_table) {
    cout << "Delete " << table_name << endl;
    if ( ! table.exists()) {
      message.reply(status_codes::NotFound);
    }
    table.delete_table();
    table_cache.delete_entry(table_name);
    message.reply(status_codes::OK);
  }
  // Delete entity
  else if (paths[0] == delete_entity) {
    // For delete entity, also need partition and row
    if (paths.size() < 4) {
	message.reply(status_codes::BadRequest);
	return;
    }
    table_entity entity {paths[2], paths[3]};
    cout << "Delete " << entity.partition_key() << " / " << entity.row_key()<< endl;

    table_operation operation {table_operation::delete_entity(entity)};
    table_result op_result {table.execute(operation)};

    int code {op_result.http_status_code()};
    if (code == status_codes::OK ||
	code == status_codes::NoContent)
      message.reply(status_codes::OK);
    else
      message.reply(code);
  }
  else {
    message.reply(status_codes::BadRequest);
  }
}

/*
  Main server routine

  Install handlers for the HTTP requests and open the listener,
  which processes each request asynchronously.

  Wait for a carriage return, then shut the server down.
 */
int main (int argc, char const * argv[]) {
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get);
  listener.support(methods::POST, &handle_post);
  listener.support(methods::PUT, &handle_put);
  listener.support(methods::DEL, &handle_delete);
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<|endoftext|>


<commit_before>#include <stan/math/prim/scal.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <gtest/gtest.h>
#include <limits>

template <typename T_N, typename T_n>
void test_binom_coefficient(const T_N& N, const T_n& n) {
  using stan::math::binomial_coefficient_log;
  EXPECT_FLOAT_EQ(lgamma(N + 1) - lgamma(n + 1) - lgamma(N - n + 1),
                  binomial_coefficient_log(N, n));
}

TEST(MathFunctions, binomial_coefficient_log) {
  using stan::math::binomial_coefficient_log;
  EXPECT_FLOAT_EQ(1.0, exp(binomial_coefficient_log(2.0, 2.0)));
  EXPECT_FLOAT_EQ(2.0, exp(binomial_coefficient_log(2.0, 1.0)));
  EXPECT_FLOAT_EQ(3.0, exp(binomial_coefficient_log(3.0, 1.0)));
  EXPECT_NEAR(3.0, exp(binomial_coefficient_log(3.0, 2.0)), 0.0001);

  EXPECT_FLOAT_EQ(29979.16, binomial_coefficient_log(100000, 91116));

  for (int n = 0; n < 1010; ++n) {
    test_binom_coefficient(1010, n);
    test_binom_coefficient(1010.0, n);
    test_binom_coefficient(1010, static_cast<double>(n));
    test_binom_coefficient(1010.0, static_cast<double>(n));
  }

  test_binom_coefficient(1e9, 1e5);
  // this overflows with boost lgamma and results in NaN comparisons
  // TODO(SW): investigate
  // test_binom_coefficient(1e50, 1e45);
}

TEST(MathFunctions, binomial_coefficient_log_nan) {
  double nan = std::numeric_limits<double>::quiet_NaN();

  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binomial_coefficient_log(2.0, nan));
  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binomial_coefficient_log(nan, 2.0));
  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binomial_coefficient_log(nan, nan));
}
<commit_msg>reenable large number test for binomial_coefficient_log_test<commit_after>#include <stan/math/prim/scal.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <gtest/gtest.h>
#include <limits>
#include <cmath>

template <typename T_N, typename T_n>
void test_binom_coefficient(const T_N& N, const T_n& n) {
  using stan::math::binomial_coefficient_log;
  EXPECT_FLOAT_EQ(lgamma(N + 1) - lgamma(n + 1) - lgamma(N - n + 1),
                  binomial_coefficient_log(N, n));
}

TEST(MathFunctions, binomial_coefficient_log) {
  using stan::math::binomial_coefficient_log;
  EXPECT_FLOAT_EQ(1.0, exp(binomial_coefficient_log(2.0, 2.0)));
  EXPECT_FLOAT_EQ(2.0, exp(binomial_coefficient_log(2.0, 1.0)));
  EXPECT_FLOAT_EQ(3.0, exp(binomial_coefficient_log(3.0, 1.0)));
  EXPECT_NEAR(3.0, exp(binomial_coefficient_log(3.0, 2.0)), 0.0001);

  EXPECT_FLOAT_EQ(29979.16, binomial_coefficient_log(100000, 91116));

  for (int n = 0; n < 1010; ++n) {
    test_binom_coefficient(1010, n);
    test_binom_coefficient(1010.0, n);
    test_binom_coefficient(1010, static_cast<double>(n));
    test_binom_coefficient(1010.0, static_cast<double>(n));
  }

  test_binom_coefficient(1e9, 1e5);

  // NOTE(SW): 2019-05-31 replaced large number test as
  // this overflows with boost lgamma and results in NaN comparisons
  // which always fail
  // test_binom_coefficient(1e50, 1e45);
  // 1E25 seems the largest number for lgamma from boost to handle
  test_binom_coefficient(1e25, 1e20);
}

TEST(MathFunctions, binomial_coefficient_log_nan) {
  double nan = std::numeric_limits<double>::quiet_NaN();

  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binomial_coefficient_log(2.0, nan));
  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binomial_coefficient_log(nan, 2.0));
  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::binomial_coefficient_log(nan, nan));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: transliteration_Numeric.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 09:32:20 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_i18npool.hxx"

#include <transliteration_Numeric.hxx>
#include <nativenumbersupplier.hxx>
#include <defaultnumberingprovider.hxx>

using namespace com::sun::star::uno;
using namespace rtl;

namespace com { namespace sun { namespace star { namespace i18n {

sal_Int16 SAL_CALL transliteration_Numeric::getType() throw(RuntimeException)
{
        return TransliterationType::NUMERIC;
}

OUString SAL_CALL
transliteration_Numeric::folding( const OUString& /*inStr*/, sal_Int32 /*startPos*/, sal_Int32 /*nCount*/, Sequence< sal_Int32 >& /*offset*/ )
        throw(RuntimeException)
{
        throw (new RuntimeException());
}

sal_Bool SAL_CALL
transliteration_Numeric::equals( const OUString& /*str1*/, sal_Int32 /*pos1*/, sal_Int32 /*nCount1*/, sal_Int32& /*nMatch1*/, const OUString& /*str2*/, sal_Int32 /*pos2*/, sal_Int32 /*nCount2*/, sal_Int32& /*nMatch2*/ )
        throw(RuntimeException)
{
        throw (new RuntimeException());
}

Sequence< OUString > SAL_CALL
transliteration_Numeric::transliterateRange( const OUString& /*str1*/, const OUString& /*str2*/ )
        throw(RuntimeException)
{
        throw (new RuntimeException());
}

#define isNumber(c) ((c) >= 0x30 && (c) <= 0x39)
#define NUMBER_ZERO 0x30

OUString SAL_CALL
transliteration_Numeric::transliterateBullet( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
        Sequence< sal_Int32 >& offset ) throw(RuntimeException)
{
        sal_Int32 number = -1, j = 0, endPos = startPos + nCount;

        if (endPos >  inStr.getLength())
            endPos = inStr.getLength();

        rtl_uString* pStr = x_rtl_uString_new_WithLength( nCount, 1 );  // our x_rtl_ustring.h
        sal_Unicode* out = pStr->buffer;

        if (useOffset)
            offset.realloc(nCount);

        for (sal_Int32 i = startPos; i < endPos; i++) {
            if (i < endPos && isNumber(inStr[i])) {
                if (number == -1) {
                    startPos = i;
                    number = (inStr[i] - NUMBER_ZERO);
                } else  {
                    number = number * 10 + (inStr[i] - NUMBER_ZERO);
                }
            } else {
                if (number == 0) {
                    if (useOffset)
                        offset[j] = startPos;
                    out[j++] = NUMBER_ZERO;
                } if (number > tableSize && !recycleSymbol) {
                    for (sal_Int32 k = startPos; k < i; k++) {
                        if (useOffset)
                            offset[j] = k;
                        out[j++] = inStr[k];
                    }
                } else if (number > 0) {
                    if (useOffset)
                        offset[j] = startPos;
                    out[j++] = table[--number % tableSize];
                } else if (i < endPos) {
                    if (useOffset)
                        offset[j] = i;
                    out[j++] = inStr[i];
                }
                number = -1;
            }
        }
        out[j] = 0;

        if (useOffset)
            offset.realloc(j);

        return OUString( pStr, SAL_NO_ACQUIRE );
}

OUString SAL_CALL
transliteration_Numeric::transliterate( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
        Sequence< sal_Int32 >& offset ) throw(RuntimeException)
{
        if (tableSize)
            return transliterateBullet( inStr, startPos, nCount, offset);
        else
            return NativeNumberSupplier(useOffset).getNativeNumberString( inStr.copy(startPos, nCount), aLocale, nNativeNumberMode, offset );
}

sal_Unicode SAL_CALL
transliteration_Numeric::transliterateChar2Char( sal_Unicode inChar ) throw(RuntimeException, MultipleCharsOutputException)
{
        if (tableSize) {
            if (isNumber(inChar)) {
                sal_Int16 number = inChar - NUMBER_ZERO;
                if (number <= tableSize || recycleSymbol)
                    return table[--number % tableSize];
            }
            return inChar;
        }
        else
            return NativeNumberSupplier().getNativeNumberChar( inChar, aLocale, nNativeNumberMode );
}

} } } }
<commit_msg>INTEGRATION: CWS changefileheader (1.7.138); FILE MERGED 2008/03/31 16:01:33 rt 1.7.138.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: transliteration_Numeric.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_i18npool.hxx"

#include <transliteration_Numeric.hxx>
#include <nativenumbersupplier.hxx>
#include <defaultnumberingprovider.hxx>

using namespace com::sun::star::uno;
using namespace rtl;

namespace com { namespace sun { namespace star { namespace i18n {

sal_Int16 SAL_CALL transliteration_Numeric::getType() throw(RuntimeException)
{
        return TransliterationType::NUMERIC;
}

OUString SAL_CALL
transliteration_Numeric::folding( const OUString& /*inStr*/, sal_Int32 /*startPos*/, sal_Int32 /*nCount*/, Sequence< sal_Int32 >& /*offset*/ )
        throw(RuntimeException)
{
        throw (new RuntimeException());
}

sal_Bool SAL_CALL
transliteration_Numeric::equals( const OUString& /*str1*/, sal_Int32 /*pos1*/, sal_Int32 /*nCount1*/, sal_Int32& /*nMatch1*/, const OUString& /*str2*/, sal_Int32 /*pos2*/, sal_Int32 /*nCount2*/, sal_Int32& /*nMatch2*/ )
        throw(RuntimeException)
{
        throw (new RuntimeException());
}

Sequence< OUString > SAL_CALL
transliteration_Numeric::transliterateRange( const OUString& /*str1*/, const OUString& /*str2*/ )
        throw(RuntimeException)
{
        throw (new RuntimeException());
}

#define isNumber(c) ((c) >= 0x30 && (c) <= 0x39)
#define NUMBER_ZERO 0x30

OUString SAL_CALL
transliteration_Numeric::transliterateBullet( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
        Sequence< sal_Int32 >& offset ) throw(RuntimeException)
{
        sal_Int32 number = -1, j = 0, endPos = startPos + nCount;

        if (endPos >  inStr.getLength())
            endPos = inStr.getLength();

        rtl_uString* pStr = x_rtl_uString_new_WithLength( nCount, 1 );  // our x_rtl_ustring.h
        sal_Unicode* out = pStr->buffer;

        if (useOffset)
            offset.realloc(nCount);

        for (sal_Int32 i = startPos; i < endPos; i++) {
            if (i < endPos && isNumber(inStr[i])) {
                if (number == -1) {
                    startPos = i;
                    number = (inStr[i] - NUMBER_ZERO);
                } else  {
                    number = number * 10 + (inStr[i] - NUMBER_ZERO);
                }
            } else {
                if (number == 0) {
                    if (useOffset)
                        offset[j] = startPos;
                    out[j++] = NUMBER_ZERO;
                } if (number > tableSize && !recycleSymbol) {
                    for (sal_Int32 k = startPos; k < i; k++) {
                        if (useOffset)
                            offset[j] = k;
                        out[j++] = inStr[k];
                    }
                } else if (number > 0) {
                    if (useOffset)
                        offset[j] = startPos;
                    out[j++] = table[--number % tableSize];
                } else if (i < endPos) {
                    if (useOffset)
                        offset[j] = i;
                    out[j++] = inStr[i];
                }
                number = -1;
            }
        }
        out[j] = 0;

        if (useOffset)
            offset.realloc(j);

        return OUString( pStr, SAL_NO_ACQUIRE );
}

OUString SAL_CALL
transliteration_Numeric::transliterate( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
        Sequence< sal_Int32 >& offset ) throw(RuntimeException)
{
        if (tableSize)
            return transliterateBullet( inStr, startPos, nCount, offset);
        else
            return NativeNumberSupplier(useOffset).getNativeNumberString( inStr.copy(startPos, nCount), aLocale, nNativeNumberMode, offset );
}

sal_Unicode SAL_CALL
transliteration_Numeric::transliterateChar2Char( sal_Unicode inChar ) throw(RuntimeException, MultipleCharsOutputException)
{
        if (tableSize) {
            if (isNumber(inChar)) {
                sal_Int16 number = inChar - NUMBER_ZERO;
                if (number <= tableSize || recycleSymbol)
                    return table[--number % tableSize];
            }
            return inChar;
        }
        else
            return NativeNumberSupplier().getNativeNumberChar( inChar, aLocale, nNativeNumberMode );
}

} } } }
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.

#pragma once

#include "iceoryx_utils/cxx/optional.hpp"
#include "iceoryx_utils/cxx/vector.hpp"
#include "iceoryx_utils/design_pattern/creation.hpp"
#include "iceoryx_utils/internal/units/duration.hpp"

#include <atomic>
#include <condition_variable>
#include <cstdint>
#include <limits>
#include <signal.h>
#include <sys/time.h>
#include <time.h>

namespace iox
{
namespace posix
{
enum class TimerError
{
    NO_ERROR,
    TIMER_NOT_INITIALIZED,
    NO_VALID_CALLBACK,
    KERNEL_ALLOC_FAILED,
    INVALID_ARGUMENTS,
    ALLOC_MEM_FAILED,
    NO_PERMISSION,
    INVALID_POINTER,
    NO_TIMER_TO_DELETE,
    INTERNAL_LOGIC_ERROR
};

using namespace iox::units::duration_literals;

/// @brief Interface for timers on POSIX operating systems
/// @note Can't be copied or moved as operating system has a pointer to this object. It needs to be ensured that this
/// object lives longer than timeToWait, otherwise the operating system will unregister the timer
/// @concurrent not thread safe
///
/// @code
///     posix::Timer& TiborTheTimer = posix::Timer::getInstance(100_ms, [&]() { fooBar++; });
///
///     // Start a periodic timer
///     TiborTheTimer.start(true);
///     // [.. wait ..]
///     // Timer fires after 100_ms and calls the lambda which increments fooBar
///
///     TiborTheTimer.stop();
///
/// @endcode
class Timer
{
  public:
    enum class RunMode
    {
        ONCE,
        PERIODIC
    };

  private:
    static constexpr size_t SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR = sizeof(uint32_t);
    static constexpr size_t SIZE_OF_SIGVAL_INT = sizeof(int);
    static_assert(SIZE_OF_SIGVAL_INT >= SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR, "size of sigval_int is to low");

    static constexpr uint32_t MAX_NUMBER_OF_CALLBACK_HANDLES = 100;
    static_assert(MAX_NUMBER_OF_CALLBACK_HANDLES <= std::numeric_limits<uint8_t>::max(),
                  "number of callback handles exceeds max index value");
    class OsTimer;
    struct OsTimerCallbackHandle
    {
        static constexpr uint32_t MAX_DESCRIPTOR_VALUE{(2 ^ 24) - 1};
        static sigval indexAndDescriptorToSigval(uint8_t index, uint32_t descriptor);
        static uint8_t sigvalToIndex(sigval intVal);
        static uint32_t sigvalToDescriptor(sigval intVal);

        void incrementDescriptor();

        std::mutex m_accessMutex;

        /// @brief the descriptor is unique for a timer_t in OsTimer, if this handle is recycled, the descriptor needs
        /// to be incremented first
        std::atomic<uint32_t> m_descriptor{0};

        std::atomic<bool> m_inUse{false};
        std::atomic<bool> m_isTimerActive{false};

        OsTimer* m_timer{nullptr};
    };

    class OsTimer
    {
#ifdef __QNX__
        static constexpr timer_t INVALID_TIMER_ID = 0;
#else
        static constexpr timer_t INVALID_TIMER_ID = nullptr;
#endif
      public:
        /// @brief Wrapper that can be registered with the operating system
        static void callbackHelper(sigval data);

        OsTimer(units::Duration timeToWait, std::function<void()> callback) noexcept;

        OsTimer(const OsTimer&) = delete;
        OsTimer(OsTimer&&) = delete;
        OsTimer& operator=(const OsTimer&) = delete;
        OsTimer& operator=(OsTimer&&) = delete;

        /// @brief D'tor
        virtual ~OsTimer() noexcept;

        /// @brief Starts the timer
        ///
        /// The callback is called by the operating system after the time has expired.
        ///
        /// @param[in] periodic - can be a periodic timer if set to true, default false
        /// @note Shall only be called when callback is given
        cxx::expected<TimerError> start(const RunMode runMode) noexcept;

        /// @brief Disarms the timer
        /// @note Shall only be called when callback is given, guarantee after stop() call is callback is immediately
        /// called or never at all
        cxx::expected<TimerError> stop() noexcept;

        /// @brief Disarms the timer, assigns a new timeToWait value and arms the timer
        /// @note Shall only be called when callback is given
        cxx::expected<TimerError> restart(const units::Duration timeToWait, const RunMode runMode) noexcept;

        // @brief Returns the time until the timer expires the next time
        /// @note Shall only be called when callback is given
        cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;

        /// @brief In case the callback is not immediately called by the operating system, getOverruns() returns the
        /// additional overruns that happended in the delay interval
        /// @note Shall only be called when callback is given
        cxx::expected<uint64_t, TimerError> getOverruns() noexcept;

        /// @brief Returns true if the construction of the object was successful
        bool hasError() const noexcept;

        /// @brief Returns the error that occured on constructing the object
        cxx::error<TimerError> getError() const noexcept;

      private:
        /// @brief Call the user-defined callback
        /// @note This call is wrapped in a plain C function
        void executeCallback() noexcept;

      private:
        /// @brief Duration after the timer calls the user-defined callback function
        units::Duration m_timeToWait;

        /// @brief Stores the user-defined callback
        std::function<void()> m_callback;

        /// @brief Identifier for the timer in the operating system
        timer_t m_timerId{INVALID_TIMER_ID};

        uint8_t m_callbackHandleIndex{0};

        /// @todo will be obsolete with creation pattern
        /// @brief Bool that signals whether the object is fully initalized
        bool m_isInitialized{false};

        /// @todo creation pattern
        /// @brief If an error happened during creation the value is stored in here
        TimerError m_errorValue{TimerError::NO_ERROR};

        static OsTimerCallbackHandle s_callbackHandlePool[MAX_NUMBER_OF_CALLBACK_HANDLES];
    };

  public:
    /// @brief Creates a timer without an operating system callback
    ///
    /// Creates a light-weight timer object that can be used with
    ///               * hasExpiredComparedToCreationTime()
    ///               * resetCreationTime()
    ///
    /// @param[in] timeToWait - How long should be waited?
    /// @note Does not set up an operating system timer, but uses CLOCK_REALTIME instead
    /// @todo refactor this cTor and its functionality to a class called StopWatch
    Timer(units::Duration timeToWait) noexcept;

    /// @brief Creates a timer with an operating system callback
    ///
    /// Initially the timer is stopped.
    ///
    /// @param[in] timeToWait - How long should be waited?
    /// @param[in] callback - Function called after timeToWait (User needs to ensure lifetime of function till stop()
    ///                       call)
    /// @note Operating systems needs a valid reference to this object, hence DesignPattern::Creation can't be used
    Timer(units::Duration timeToWait, std::function<void()> callback) noexcept;

    /// @brief creates Duration from the result of clock_gettime(CLOCK_REALTIME, ...)
    /// @return if the clock_gettime call failed TimerError is returned otherwise Duration
    /// @todo maybe move this to a clock implementation?
    static cxx::expected<units::Duration, TimerError> now() noexcept;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer(const Timer& other) = delete;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer(Timer&& other) = delete;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer& operator=(const Timer& other) = delete;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer& operator=(Timer&& other) = delete;

    /// @brief D'tor
    virtual ~Timer() noexcept = default;

    /// @brief Starts the timer
    ///
    /// The callback is called by the operating system after the time has expired.
    ///
    /// @param[in] periodic - can be a periodic timer if set to true, default false
    /// @note Shall only be called when callback is given
    /// @todo replace bool with enum; SingleShot and Periodic
    cxx::expected<TimerError> start(const RunMode runMode) noexcept;

    /// @brief Disarms the timer
    /// @note Shall only be called when callback is given, guarantee after stop() call is callback is immediately
    /// called or never at all
    cxx::expected<TimerError> stop() noexcept;

    /// @brief Disarms the timer, assigns a new timeToWait value and arms the timer
    /// @note Shall only be called when callback is given
    cxx::expected<TimerError> restart(const units::Duration timeToWait, const RunMode runMode) noexcept;

    /// @brief Resets the internal creation time
    void resetCreationTime() noexcept;

    /// @brief Checks if the timer has expired compared to its creation time
    /// @return Is the elapsed time larger than timeToWait?
    bool hasExpiredComparedToCreationTime() noexcept;

    // @brief Returns the time until the timer expires the next time
    /// @note Shall only be called when callback is given
    cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;

    /// @brief In case the callback is not immediately called by the operating system, getOverruns() returns the
    /// additional overruns that happended in the delay interval
    /// @note Shall only be called when callback is given
    cxx::expected<uint64_t, TimerError> getOverruns() noexcept;

    /// @brief Returns true if the construction of the object was successful
    bool hasError() const noexcept;

    /// @brief Returns the error that occured on constructing the object
    cxx::error<TimerError> getError() const noexcept;

  private:
    cxx::optional<OsTimer> m_osTimer;

    /// @brief Converts errnum to TimerError
    static cxx::error<TimerError> createErrorFromErrno(const int errnum) noexcept;

    /// @brief Duration after the timer calls the user-defined callback function
    units::Duration m_timeToWait;

    /// @brief Time when the timer object was created
    units::Duration m_creationTime;

    /// @brief If an error happened during creation the value is stored in here
    TimerError m_errorValue{TimerError::NO_ERROR};
};

} // namespace posix
} // namespace iox
<commit_msg>iox-#17 Update timer usage in example<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.

#pragma once

#include "iceoryx_utils/cxx/optional.hpp"
#include "iceoryx_utils/cxx/vector.hpp"
#include "iceoryx_utils/design_pattern/creation.hpp"
#include "iceoryx_utils/internal/units/duration.hpp"

#include <atomic>
#include <condition_variable>
#include <cstdint>
#include <limits>
#include <signal.h>
#include <sys/time.h>
#include <time.h>

namespace iox
{
namespace posix
{
enum class TimerError
{
    NO_ERROR,
    TIMER_NOT_INITIALIZED,
    NO_VALID_CALLBACK,
    KERNEL_ALLOC_FAILED,
    INVALID_ARGUMENTS,
    ALLOC_MEM_FAILED,
    NO_PERMISSION,
    INVALID_POINTER,
    NO_TIMER_TO_DELETE,
    INTERNAL_LOGIC_ERROR
};

using namespace iox::units::duration_literals;

/// @brief Interface for timers on POSIX operating systems
/// @note Can't be copied or moved as operating system has a pointer to this object. It needs to be ensured that this
/// object lives longer than timeToWait, otherwise the operating system will unregister the timer
/// @concurrent not thread safe
///
/// @code
///     posix::Timer TiborTheTimer{100_ms, [&]() { fooBar++; }};
///
///     // Start a periodic timer
///     TiborTheTimer.start(true);
///     // [.. wait ..]
///     // Timer fires after 100_ms and calls the lambda which increments fooBar
///
///     TiborTheTimer.stop();
///
/// @endcode
class Timer
{
  public:
    enum class RunMode
    {
        ONCE,
        PERIODIC
    };

  private:
    static constexpr size_t SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR = sizeof(uint32_t);
    static constexpr size_t SIZE_OF_SIGVAL_INT = sizeof(int);
    static_assert(SIZE_OF_SIGVAL_INT >= SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR, "size of sigval_int is to low");

    static constexpr uint32_t MAX_NUMBER_OF_CALLBACK_HANDLES = 100;
    static_assert(MAX_NUMBER_OF_CALLBACK_HANDLES <= std::numeric_limits<uint8_t>::max(),
                  "number of callback handles exceeds max index value");
    class OsTimer;
    struct OsTimerCallbackHandle
    {
        static constexpr uint32_t MAX_DESCRIPTOR_VALUE{(2 ^ 24) - 1};
        static sigval indexAndDescriptorToSigval(uint8_t index, uint32_t descriptor);
        static uint8_t sigvalToIndex(sigval intVal);
        static uint32_t sigvalToDescriptor(sigval intVal);

        void incrementDescriptor();

        std::mutex m_accessMutex;

        /// @brief the descriptor is unique for a timer_t in OsTimer, if this handle is recycled, the descriptor needs
        /// to be incremented first
        std::atomic<uint32_t> m_descriptor{0};

        std::atomic<bool> m_inUse{false};
        std::atomic<bool> m_isTimerActive{false};

        OsTimer* m_timer{nullptr};
    };

    class OsTimer
    {
#ifdef __QNX__
        static constexpr timer_t INVALID_TIMER_ID = 0;
#else
        static constexpr timer_t INVALID_TIMER_ID = nullptr;
#endif
      public:
        /// @brief Wrapper that can be registered with the operating system
        static void callbackHelper(sigval data);

        OsTimer(units::Duration timeToWait, std::function<void()> callback) noexcept;

        OsTimer(const OsTimer&) = delete;
        OsTimer(OsTimer&&) = delete;
        OsTimer& operator=(const OsTimer&) = delete;
        OsTimer& operator=(OsTimer&&) = delete;

        /// @brief D'tor
        virtual ~OsTimer() noexcept;

        /// @brief Starts the timer
        ///
        /// The callback is called by the operating system after the time has expired.
        ///
        /// @param[in] periodic - can be a periodic timer if set to true, default false
        /// @note Shall only be called when callback is given
        cxx::expected<TimerError> start(const RunMode runMode) noexcept;

        /// @brief Disarms the timer
        /// @note Shall only be called when callback is given, guarantee after stop() call is callback is immediately
        /// called or never at all
        cxx::expected<TimerError> stop() noexcept;

        /// @brief Disarms the timer, assigns a new timeToWait value and arms the timer
        /// @note Shall only be called when callback is given
        cxx::expected<TimerError> restart(const units::Duration timeToWait, const RunMode runMode) noexcept;

        // @brief Returns the time until the timer expires the next time
        /// @note Shall only be called when callback is given
        cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;

        /// @brief In case the callback is not immediately called by the operating system, getOverruns() returns the
        /// additional overruns that happended in the delay interval
        /// @note Shall only be called when callback is given
        cxx::expected<uint64_t, TimerError> getOverruns() noexcept;

        /// @brief Returns true if the construction of the object was successful
        bool hasError() const noexcept;

        /// @brief Returns the error that occured on constructing the object
        cxx::error<TimerError> getError() const noexcept;

      private:
        /// @brief Call the user-defined callback
        /// @note This call is wrapped in a plain C function
        void executeCallback() noexcept;

      private:
        /// @brief Duration after the timer calls the user-defined callback function
        units::Duration m_timeToWait;

        /// @brief Stores the user-defined callback
        std::function<void()> m_callback;

        /// @brief Identifier for the timer in the operating system
        timer_t m_timerId{INVALID_TIMER_ID};

        uint8_t m_callbackHandleIndex{0};

        /// @todo will be obsolete with creation pattern
        /// @brief Bool that signals whether the object is fully initalized
        bool m_isInitialized{false};

        /// @todo creation pattern
        /// @brief If an error happened during creation the value is stored in here
        TimerError m_errorValue{TimerError::NO_ERROR};

        static OsTimerCallbackHandle s_callbackHandlePool[MAX_NUMBER_OF_CALLBACK_HANDLES];
    };

  public:
    /// @brief Creates a timer without an operating system callback
    ///
    /// Creates a light-weight timer object that can be used with
    ///               * hasExpiredComparedToCreationTime()
    ///               * resetCreationTime()
    ///
    /// @param[in] timeToWait - How long should be waited?
    /// @note Does not set up an operating system timer, but uses CLOCK_REALTIME instead
    /// @todo refactor this cTor and its functionality to a class called StopWatch
    Timer(units::Duration timeToWait) noexcept;

    /// @brief Creates a timer with an operating system callback
    ///
    /// Initially the timer is stopped.
    ///
    /// @param[in] timeToWait - How long should be waited?
    /// @param[in] callback - Function called after timeToWait (User needs to ensure lifetime of function till stop()
    ///                       call)
    /// @note Operating systems needs a valid reference to this object, hence DesignPattern::Creation can't be used
    Timer(units::Duration timeToWait, std::function<void()> callback) noexcept;

    /// @brief creates Duration from the result of clock_gettime(CLOCK_REALTIME, ...)
    /// @return if the clock_gettime call failed TimerError is returned otherwise Duration
    /// @todo maybe move this to a clock implementation?
    static cxx::expected<units::Duration, TimerError> now() noexcept;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer(const Timer& other) = delete;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer(Timer&& other) = delete;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer& operator=(const Timer& other) = delete;

    /// @brief Move or semantics are forbidden as address of object is not allowed to change
    Timer& operator=(Timer&& other) = delete;

    /// @brief D'tor
    virtual ~Timer() noexcept = default;

    /// @brief Starts the timer
    ///
    /// The callback is called by the operating system after the time has expired.
    ///
    /// @param[in] periodic - can be a periodic timer if set to true, default false
    /// @note Shall only be called when callback is given
    /// @todo replace bool with enum; SingleShot and Periodic
    cxx::expected<TimerError> start(const RunMode runMode) noexcept;

    /// @brief Disarms the timer
    /// @note Shall only be called when callback is given, guarantee after stop() call is callback is immediately
    /// called or never at all
    cxx::expected<TimerError> stop() noexcept;

    /// @brief Disarms the timer, assigns a new timeToWait value and arms the timer
    /// @note Shall only be called when callback is given
    cxx::expected<TimerError> restart(const units::Duration timeToWait, const RunMode runMode) noexcept;

    /// @brief Resets the internal creation time
    void resetCreationTime() noexcept;

    /// @brief Checks if the timer has expired compared to its creation time
    /// @return Is the elapsed time larger than timeToWait?
    bool hasExpiredComparedToCreationTime() noexcept;

    // @brief Returns the time until the timer expires the next time
    /// @note Shall only be called when callback is given
    cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;

    /// @brief In case the callback is not immediately called by the operating system, getOverruns() returns the
    /// additional overruns that happended in the delay interval
    /// @note Shall only be called when callback is given
    cxx::expected<uint64_t, TimerError> getOverruns() noexcept;

    /// @brief Returns true if the construction of the object was successful
    bool hasError() const noexcept;

    /// @brief Returns the error that occured on constructing the object
    cxx::error<TimerError> getError() const noexcept;

  private:
    cxx::optional<OsTimer> m_osTimer;

    /// @brief Converts errnum to TimerError
    static cxx::error<TimerError> createErrorFromErrno(const int errnum) noexcept;

    /// @brief Duration after the timer calls the user-defined callback function
    units::Duration m_timeToWait;

    /// @brief Time when the timer object was created
    units::Duration m_creationTime;

    /// @brief If an error happened during creation the value is stored in here
    TimerError m_errorValue{TimerError::NO_ERROR};
};

} // namespace posix
} // namespace iox
<|endoftext|>