<commit_before>#ifndef ARABICA_DOM_UTILS_STREAM_H
#define ARABICA_DOM_UTILS_STREAM_H
///////////////////////////////////////////////////////////////////////
//
// DOM/Utils/Stream.h
//
// Written by Jez Higgins <jez@jezuk.co.uk>
// Copyright 2003-2005 Jez UK Ltd, http://www.jezuk.co.uk
//
// Provides streaming operator<< for DOM::Nodes.  Fully parameterised so
// will work with wide and narrow char types, so long as an operator<<
// exists for the DOM::Node's string_type.
//
// e.g.
//  Arabica::SAX2DOM::Parser<std::wstring> domParser;
//  SAX::wInputSource is;
//  ... load instance from somewhere ...
//  domParser.parse(is);
//  DOM::Document<std::wstring> doc = domParser.getDocument();
//  ... manipulate doc ...
//  std::wcout << doc;
//
///////////////////////////////////////////////////////////////////////
// $Id$
///////////////////////////////////////////////////////////////////////

#include <iostream>
#include <algorithm>
#include <text/UnicodeCharacters.hpp>
#include <XML/escaper.hpp>

namespace Arabica
{
namespace DOM
{

namespace StreamImpl
{
template<class stringT, class string_adaptorT, class charT, class traitsT>
void streamChildren(std::basic_ostream<charT, traitsT>& stream, DOM::Node<stringT, string_adaptorT>& node)
{
  DOM::Node<stringT> child = node.getFirstChild();
  while(child != 0)
  {
    stream << child;
    child = child.getNextSibling();
  } // while
} // streamChildren

template<class stringT>
void prefix_mapper_callback(std::ios_base::event ev, std::ios_base& stream, int index)
{
  if(ev == std::ios_base::erase_event)
    delete static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));
} // boing_callback

template<class stringT>
std::pair<bool, stringT> is_uri_declared(std::vector<std::map<stringT, stringT> >* prefix_stack, const stringT& namespaceURI)
{
  stringT declared_prefix;
  for(typename std::vector<std::map<stringT, stringT> >::reverse_iterator b = prefix_stack->rbegin(), e = prefix_stack->rend();
        b != e;
        ++b)
  {
    typename std::map<stringT, stringT>::const_iterator p = b->find(namespaceURI);
    if(p != b->end())
      return std::make_pair(true, p->second);
  } // for ...

  return std::make_pair(false, stringT());
} // prefix_is_declared

template<class stringT, class string_adaptorT, class charT, class traitsT>
void check_and_output_node_name(std::basic_ostream<charT, traitsT>& stream,
                                DOM::Node<stringT, string_adaptorT>& node,
                                std::vector<std::map<stringT, stringT> >* prefix_stack)
{
  std::map<stringT, stringT>& current = *(prefix_stack->rbegin());

  stringT namespaceURI = node.getNamespaceURI();
  if(!namespaceURI.empty())
  {
    std::pair<bool, stringT> prefix = is_uri_declared(prefix_stack, namespaceURI);

    if(!prefix.first)
      current[namespaceURI] =  prefix.second = node.getPrefix();

    if(!prefix.second.empty())
      stream << prefix.second << Arabica::text::Unicode<charT>::COLON;
    stream << node.getLocalName();
  }
  else
    stream << node.getNodeName();
} // check_and_output_node_name

template<class stringT, class charT>
bool isXmlns(const stringT& str)
{
  typedef Arabica::text::Unicode<charT> UnicodeT;

  if(str.size() != 5)
    return false;

  if((str[0] == UnicodeT::LOWERCASE_X) &&
     (str[1] == UnicodeT::LOWERCASE_M) &&
     (str[2] == UnicodeT::LOWERCASE_L) &&
     (str[3] == UnicodeT::LOWERCASE_N) &&
     (str[4] == UnicodeT::LOWERCASE_S))
    return true;
  return false;
} // isXmlns

template<class stringT, class string_adaptorT, class charT, class traitsT>
int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
                   DOM::Node<stringT, string_adaptorT>& node)
{
  typedef Arabica::text::Unicode<charT> UnicodeT;

  static const int index = std::ios_base::xalloc();
  std::vector<std::map<stringT, stringT> >* prefix_stack;

  if(stream.pword(index) != 0)
  {
    prefix_stack = static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));
    prefix_stack->push_back(std::map<stringT, stringT>());
  }
  else
  {
    prefix_stack = new std::vector<std::map<stringT, stringT> >;
    stream.pword(index) = prefix_stack;

    std::map<stringT, stringT> prefixes;
    for(DOM::Node<stringT> p = node.getParentNode(); p.getNodeType() == DOM::Node_base::ELEMENT_NODE; p = p.getParentNode())
    {
      if(p.getNamespaceURI().empty())
        continue;
      if(prefixes.find(p.getNamespaceURI()) == prefixes.end())
        prefixes[p.getNamespaceURI()] = p.getPrefix();
    } // for ...

    prefix_stack->push_back(prefixes);
  } // if ...

  std::map<stringT, stringT>& current = *(prefix_stack->rbegin());

  // is element namespace URI declared?
  check_and_output_node_name(stream, node, prefix_stack);

  DOM::NamedNodeMap<stringT> attrs = node.getAttributes();
  std::vector<stringT> names;
  for(unsigned int a = 0; a < attrs.getLength(); ++a)
    names.push_back(attrs.item(a).getNodeName());
  std::sort(names.begin(), names.end());

  for(typename std::vector<stringT>::const_iterator a = names.begin(), ae = names.end(); a != ae; ++a)
  {
    DOM::Node<stringT> attr = attrs.getNamedItem(*a);
    if(isXmlns<stringT, charT>(attr.getNodeName()) ||
       isXmlns<stringT, charT>(attr.getPrefix()))
      continue;
    stream << UnicodeT::SPACE;
    check_and_output_node_name(stream, attr, prefix_stack);
    stream  << UnicodeT::EQUALS_SIGN
            << UnicodeT::QUOTATION_MARK;
    stringT value = attr.getNodeValue();
    std::for_each(value.begin(), value.end(), Arabica::XML::attribute_escaper<charT, traitsT>(stream));
    stream << UnicodeT::QUOTATION_MARK;
  }

  for(typename std::map<stringT, stringT>::const_iterator i = current.begin(), e = current.end();
      i != e;
      ++i)
  {
    stream << UnicodeT::SPACE
           << UnicodeT::LOWERCASE_X
           << UnicodeT::LOWERCASE_M
           << UnicodeT::LOWERCASE_L
           << UnicodeT::LOWERCASE_N
           << UnicodeT::LOWERCASE_S;
    if(!(i->second.empty()))
      stream << UnicodeT::COLON << i->second;
    stream << UnicodeT::EQUALS_SIGN << UnicodeT::QUOTATION_MARK;
    std::for_each(i->first.begin(), i->first.end(), Arabica::XML::attribute_escaper<charT, traitsT>(stream));
    stream << UnicodeT::QUOTATION_MARK;
  } // for ...

  return index;
} // prefix_mapper

template<class stringT, class string_adaptorT, class charT, class traitsT>
void prefix_mapper_pop(std::basic_ostream<charT, traitsT>& stream,
                       DOM::Node<stringT, string_adaptorT> node,
                       int index)
{
  std::vector<std::map<stringT, stringT> >* prefix_stack =
    static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));

  check_and_output_node_name(stream, node, prefix_stack);

  prefix_stack->pop_back();
  if(prefix_stack->empty())
  {
    delete static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));
    stream.pword(index) = 0;
  } // if ...
} // prefix_mapper_pop

} // namespace StreamImpl

template<class stringT, class string_adaptorT, class charT, class traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& stream,
           DOM::Node<stringT, string_adaptorT>& node)
{
  typedef Arabica::text::Unicode<charT> UnicodeT;

  switch(node.getNodeType())
  {
  case DOM::Node<stringT>::DOCUMENT_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::QUESTION_MARK
           << UnicodeT::LOWERCASE_X
           << UnicodeT::LOWERCASE_M
           << UnicodeT::LOWERCASE_L
           << UnicodeT::SPACE
           << UnicodeT::LOWERCASE_V
           << UnicodeT::LOWERCASE_E
           << UnicodeT::LOWERCASE_R
           << UnicodeT::LOWERCASE_S
           << UnicodeT::LOWERCASE_I
           << UnicodeT::LOWERCASE_O
           << UnicodeT::LOWERCASE_N
           << UnicodeT::EQUALS_SIGN
           << UnicodeT::QUOTATION_MARK
           << UnicodeT::NUMBER_1
           << UnicodeT::FULL_STOP
           << UnicodeT::NUMBER_0
           << UnicodeT::QUOTATION_MARK
           << UnicodeT::QUESTION_MARK
           << UnicodeT::GREATER_THAN_SIGN
           << std::endl;
  case DOM::Node<stringT>::DOCUMENT_FRAGMENT_NODE:
    StreamImpl::streamChildren(stream, node);
    break;
  case DOM::Node<stringT>::ELEMENT_NODE:
    {
      stream << UnicodeT::LESS_THAN_SIGN;
      int index = StreamImpl::prefix_mapper(stream, node);
      stream << UnicodeT::GREATER_THAN_SIGN;
      StreamImpl::streamChildren(stream, node);
      stream << UnicodeT::LESS_THAN_SIGN << UnicodeT::SLASH;
      StreamImpl::prefix_mapper_pop(stream, node, index);
      stream << UnicodeT::GREATER_THAN_SIGN;
    }
    break;
  case DOM::Node<stringT>::TEXT_NODE:
    {
      stringT value = node.getNodeValue();
      std::for_each(value.begin(), value.end(), Arabica::XML::text_escaper<charT, traitsT>(stream));
    }
    break;
  case DOM::Node<stringT>::ENTITY_REFERENCE_NODE:
    stream << UnicodeT::AMPERSAND
           << node.getNodeName()
           << UnicodeT::SEMI_COLON;
    break;
  case DOM::Node<stringT>::CDATA_SECTION_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::EXCLAMATION_MARK
           << UnicodeT::LEFT_SQUARE_BRACKET
           << UnicodeT::CAPITAL_C
           << UnicodeT::CAPITAL_D
           << UnicodeT::CAPITAL_A
           << UnicodeT::CAPITAL_T
           << UnicodeT::CAPITAL_A
           << UnicodeT::LEFT_SQUARE_BRACKET
           << node.getNodeValue()
           << UnicodeT::RIGHT_SQUARE_BRACKET
           << UnicodeT::RIGHT_SQUARE_BRACKET
           << UnicodeT::GREATER_THAN_SIGN;
    break;
  case DOM::Node<stringT>::PROCESSING_INSTRUCTION_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::QUESTION_MARK
           << node.getNodeName()
           << UnicodeT::SPACE
           << node.getNodeValue()
           << UnicodeT::QUESTION_MARK
           << UnicodeT::GREATER_THAN_SIGN;
    break;
  case DOM::Node<stringT>::COMMENT_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::EXCLAMATION_MARK
           << UnicodeT::HYPHEN_MINUS
           << UnicodeT::HYPHEN_MINUS
           << node.getNodeValue()
           << UnicodeT::HYPHEN_MINUS
           << UnicodeT::HYPHEN_MINUS
           << UnicodeT::GREATER_THAN_SIGN;
    break;
  default: // keep GCC quiet
	  break;
  } // switch

  return stream;
} // operator<<

} // namespace DOM
} // namespace Arabica

#endif
<commit_msg>DOM stream now outputs <elem/> for empty elements<commit_after>#ifndef ARABICA_DOM_UTILS_STREAM_H
#define ARABICA_DOM_UTILS_STREAM_H
///////////////////////////////////////////////////////////////////////
//
// DOM/Utils/Stream.h
//
// Written by Jez Higgins <jez@jezuk.co.uk>
// Copyright 2003-2005 Jez UK Ltd, http://www.jezuk.co.uk
//
// Provides streaming operator<< for DOM::Nodes.  Fully parameterised so
// will work with wide and narrow char types, so long as an operator<<
// exists for the DOM::Node's string_type.
//
// e.g.
//  Arabica::SAX2DOM::Parser<std::wstring> domParser;
//  SAX::wInputSource is;
//  ... load instance from somewhere ...
//  domParser.parse(is);
//  DOM::Document<std::wstring> doc = domParser.getDocument();
//  ... manipulate doc ...
//  std::wcout << doc;
//
///////////////////////////////////////////////////////////////////////
// $Id$
///////////////////////////////////////////////////////////////////////

#include <iostream>
#include <algorithm>
#include <text/UnicodeCharacters.hpp>
#include <XML/escaper.hpp>

namespace Arabica
{
namespace DOM
{

namespace StreamImpl
{
template<class stringT, class string_adaptorT, class charT, class traitsT>
void streamChildren(std::basic_ostream<charT, traitsT>& stream, DOM::Node<stringT, string_adaptorT>& node)
{
  DOM::Node<stringT> child = node.getFirstChild();
  while(child != 0)
  {
    stream << child;
    child = child.getNextSibling();
  } // while
} // streamChildren

template<class stringT>
void prefix_mapper_callback(std::ios_base::event ev, std::ios_base& stream, int index)
{
  if(ev == std::ios_base::erase_event)
    delete static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));
} // boing_callback

template<class stringT>
std::pair<bool, stringT> is_uri_declared(std::vector<std::map<stringT, stringT> >* prefix_stack, const stringT& namespaceURI)
{
  stringT declared_prefix;
  for(typename std::vector<std::map<stringT, stringT> >::reverse_iterator b = prefix_stack->rbegin(), e = prefix_stack->rend();
        b != e;
        ++b)
  {
    typename std::map<stringT, stringT>::const_iterator p = b->find(namespaceURI);
    if(p != b->end())
      return std::make_pair(true, p->second);
  } // for ...

  return std::make_pair(false, stringT());
} // prefix_is_declared

template<class stringT, class string_adaptorT, class charT, class traitsT>
void check_and_output_node_name(std::basic_ostream<charT, traitsT>& stream,
                                DOM::Node<stringT, string_adaptorT>& node,
                                std::vector<std::map<stringT, stringT> >* prefix_stack)
{
  std::map<stringT, stringT>& current = *(prefix_stack->rbegin());

  stringT namespaceURI = node.getNamespaceURI();
  if(!namespaceURI.empty())
  {
    std::pair<bool, stringT> prefix = is_uri_declared(prefix_stack, namespaceURI);

    if(!prefix.first)
      current[namespaceURI] =  prefix.second = node.getPrefix();

    if(!prefix.second.empty())
      stream << prefix.second << Arabica::text::Unicode<charT>::COLON;
    stream << node.getLocalName();
  }
  else
    stream << node.getNodeName();
} // check_and_output_node_name

template<class stringT, class charT>
bool isXmlns(const stringT& str)
{
  typedef Arabica::text::Unicode<charT> UnicodeT;

  if(str.size() != 5)
    return false;

  if((str[0] == UnicodeT::LOWERCASE_X) &&
     (str[1] == UnicodeT::LOWERCASE_M) &&
     (str[2] == UnicodeT::LOWERCASE_L) &&
     (str[3] == UnicodeT::LOWERCASE_N) &&
     (str[4] == UnicodeT::LOWERCASE_S))
    return true;
  return false;
} // isXmlns

template<class stringT, class string_adaptorT, class charT, class traitsT>
int prefix_mapper(std::basic_ostream<charT, traitsT>& stream,
                   DOM::Node<stringT, string_adaptorT>& node)
{
  typedef Arabica::text::Unicode<charT> UnicodeT;

  static const int index = std::ios_base::xalloc();
  std::vector<std::map<stringT, stringT> >* prefix_stack;

  if(stream.pword(index) != 0)
  {
    prefix_stack = static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));
    prefix_stack->push_back(std::map<stringT, stringT>());
  }
  else
  {
    prefix_stack = new std::vector<std::map<stringT, stringT> >;
    stream.pword(index) = prefix_stack;

    std::map<stringT, stringT> prefixes;
    for(DOM::Node<stringT> p = node.getParentNode(); p.getNodeType() == DOM::Node_base::ELEMENT_NODE; p = p.getParentNode())
    {
      if(p.getNamespaceURI().empty())
        continue;
      if(prefixes.find(p.getNamespaceURI()) == prefixes.end())
        prefixes[p.getNamespaceURI()] = p.getPrefix();
    } // for ...

    prefix_stack->push_back(prefixes);
  } // if ...

  std::map<stringT, stringT>& current = *(prefix_stack->rbegin());

  // is element namespace URI declared?
  check_and_output_node_name(stream, node, prefix_stack);

  DOM::NamedNodeMap<stringT> attrs = node.getAttributes();
  std::vector<stringT> names;
  for(unsigned int a = 0; a < attrs.getLength(); ++a)
    names.push_back(attrs.item(a).getNodeName());
  std::sort(names.begin(), names.end());

  for(typename std::vector<stringT>::const_iterator a = names.begin(), ae = names.end(); a != ae; ++a)
  {
    DOM::Node<stringT> attr = attrs.getNamedItem(*a);
    if(isXmlns<stringT, charT>(attr.getNodeName()) ||
       isXmlns<stringT, charT>(attr.getPrefix()))
      continue;
    stream << UnicodeT::SPACE;
    check_and_output_node_name(stream, attr, prefix_stack);
    stream  << UnicodeT::EQUALS_SIGN
            << UnicodeT::QUOTATION_MARK;
    stringT value = attr.getNodeValue();
    std::for_each(value.begin(), value.end(), Arabica::XML::attribute_escaper<charT, traitsT>(stream));
    stream << UnicodeT::QUOTATION_MARK;
  }

  for(typename std::map<stringT, stringT>::const_iterator i = current.begin(), e = current.end();
      i != e;
      ++i)
  {
    stream << UnicodeT::SPACE
           << UnicodeT::LOWERCASE_X
           << UnicodeT::LOWERCASE_M
           << UnicodeT::LOWERCASE_L
           << UnicodeT::LOWERCASE_N
           << UnicodeT::LOWERCASE_S;
    if(!(i->second.empty()))
      stream << UnicodeT::COLON << i->second;
    stream << UnicodeT::EQUALS_SIGN << UnicodeT::QUOTATION_MARK;
    std::for_each(i->first.begin(), i->first.end(), Arabica::XML::attribute_escaper<charT, traitsT>(stream));
    stream << UnicodeT::QUOTATION_MARK;
  } // for ...

  return index;
} // prefix_mapper

template<class stringT, class string_adaptorT, class charT, class traitsT>
void prefix_mapper_pop(std::basic_ostream<charT, traitsT>& stream,
                       DOM::Node<stringT, string_adaptorT> node,
                       int index,
                       bool output)
{
  std::vector<std::map<stringT, stringT> >* prefix_stack =
    static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));

  if(output)
    check_and_output_node_name(stream, node, prefix_stack);

  prefix_stack->pop_back();
  if(prefix_stack->empty())
  {
    delete static_cast<std::vector<std::map<stringT, stringT> >*>(stream.pword(index));
    stream.pword(index) = 0;
  } // if ...
} // prefix_mapper_pop

} // namespace StreamImpl

template<class stringT, class string_adaptorT, class charT, class traitsT>
std::basic_ostream<charT, traitsT>&
operator<<(std::basic_ostream<charT, traitsT>& stream,
           DOM::Node<stringT, string_adaptorT>& node)
{
  typedef Arabica::text::Unicode<charT> UnicodeT;

  switch(node.getNodeType())
  {
  case DOM::Node<stringT>::DOCUMENT_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::QUESTION_MARK
           << UnicodeT::LOWERCASE_X
           << UnicodeT::LOWERCASE_M
           << UnicodeT::LOWERCASE_L
           << UnicodeT::SPACE
           << UnicodeT::LOWERCASE_V
           << UnicodeT::LOWERCASE_E
           << UnicodeT::LOWERCASE_R
           << UnicodeT::LOWERCASE_S
           << UnicodeT::LOWERCASE_I
           << UnicodeT::LOWERCASE_O
           << UnicodeT::LOWERCASE_N
           << UnicodeT::EQUALS_SIGN
           << UnicodeT::QUOTATION_MARK
           << UnicodeT::NUMBER_1
           << UnicodeT::FULL_STOP
           << UnicodeT::NUMBER_0
           << UnicodeT::QUOTATION_MARK
           << UnicodeT::QUESTION_MARK
           << UnicodeT::GREATER_THAN_SIGN
           << std::endl;
  case DOM::Node<stringT>::DOCUMENT_FRAGMENT_NODE:
    StreamImpl::streamChildren(stream, node);
    break;
  case DOM::Node<stringT>::ELEMENT_NODE:
    {
      stream << UnicodeT::LESS_THAN_SIGN;
      int index = StreamImpl::prefix_mapper(stream, node);

      if(node.hasChildNodes())
      {
        stream << UnicodeT::GREATER_THAN_SIGN;
        StreamImpl::streamChildren(stream, node);
        stream << UnicodeT::LESS_THAN_SIGN << UnicodeT::SLASH;
        StreamImpl::prefix_mapper_pop(stream, node, index, true);
        stream << UnicodeT::GREATER_THAN_SIGN;
      }
      else
      {
        StreamImpl::prefix_mapper_pop(stream, node, index, false);
        stream << UnicodeT::SLASH << UnicodeT::GREATER_THAN_SIGN;
      }
    }
    break;
  case DOM::Node<stringT>::TEXT_NODE:
    {
      stringT value = node.getNodeValue();
      std::for_each(value.begin(), value.end(), Arabica::XML::text_escaper<charT, traitsT>(stream));
    }
    break;
  case DOM::Node<stringT>::ENTITY_REFERENCE_NODE:
    stream << UnicodeT::AMPERSAND
           << node.getNodeName()
           << UnicodeT::SEMI_COLON;
    break;
  case DOM::Node<stringT>::CDATA_SECTION_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::EXCLAMATION_MARK
           << UnicodeT::LEFT_SQUARE_BRACKET
           << UnicodeT::CAPITAL_C
           << UnicodeT::CAPITAL_D
           << UnicodeT::CAPITAL_A
           << UnicodeT::CAPITAL_T
           << UnicodeT::CAPITAL_A
           << UnicodeT::LEFT_SQUARE_BRACKET
           << node.getNodeValue()
           << UnicodeT::RIGHT_SQUARE_BRACKET
           << UnicodeT::RIGHT_SQUARE_BRACKET
           << UnicodeT::GREATER_THAN_SIGN;
    break;
  case DOM::Node<stringT>::PROCESSING_INSTRUCTION_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::QUESTION_MARK
           << node.getNodeName()
           << UnicodeT::SPACE
           << node.getNodeValue()
           << UnicodeT::QUESTION_MARK
           << UnicodeT::GREATER_THAN_SIGN;
    break;
  case DOM::Node<stringT>::COMMENT_NODE:
    stream << UnicodeT::LESS_THAN_SIGN
           << UnicodeT::EXCLAMATION_MARK
           << UnicodeT::HYPHEN_MINUS
           << UnicodeT::HYPHEN_MINUS
           << node.getNodeValue()
           << UnicodeT::HYPHEN_MINUS
           << UnicodeT::HYPHEN_MINUS
           << UnicodeT::GREATER_THAN_SIGN;
    break;
  default: // keep GCC quiet
	  break;
  } // switch

  return stream;
} // operator<<

} // namespace DOM
} // namespace Arabica

#endif
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_LIST_HXX
#define _ABACLADE_LIST_HXX

#ifndef _ABACLADE_HXX
   #error "Please #include <abaclade.hxx> before this file"
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::detail::list_impl

namespace abc {
namespace detail {

//! Non-template implementation class for abc::list.
class ABACLADE_SYM list_impl {
public:
   /*! Constructor.

   @param l
      Source object.
   */
   list_impl() :
      m_pnFirst(nullptr),
      m_pnLast(nullptr),
      m_cNodes(0) {
   }
   list_impl(list_impl && l) :
      m_pnFirst(l.m_pnFirst),
      m_pnLast(l.m_pnLast),
      m_cNodes(l.m_cNodes) {
      l.m_pnFirst = nullptr;
      l.m_pnLast = nullptr;
      l.m_cNodes = 0;
   }

   //! Destructor.
   ~list_impl() {
   }

   /*! Assignment operator.

   @param l
      Source object.
   */
   list_impl & operator=(list_impl && l);

   /*! Returns the count of elements in the list.

   @return
      Count of elements.
   */
   std::size_t size() const {
      return m_cNodes;
   }

protected:
   /*! Inserts a node to the end of the list.

   @param pn
      Pointer to the node to become the first in the list.
   */
   void link_back(xor_list_node_impl * pn);

   /*! Inserts a node to the start of the list.

   @param pn
      Pointer to the node to become the last in the list.
   */
   void link_front(xor_list_node_impl * pn);

   /*! Unlinks and returns the first node in the list.

   @return
      Former first node.
   */
   xor_list_node_impl * unlink_back();

   /*! Unlinks and returns the first node in the list.

   @return
      Former first node.
   */
   xor_list_node_impl * unlink_front();

protected:
   //! Pointer to the first node.
   xor_list_node_impl * m_pnFirst;
   //! Pointer to the last node.
   xor_list_node_impl * m_pnLast;
   //! Count of nodes.
   std::size_t m_cNodes;
};

} //namespace detail
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::list

namespace abc {

//! Doubly-linked list.
template <typename T>
class list : public detail::list_impl {
private:
   typedef detail::xor_list_node_impl node_impl;

protected:
   //! List node.
   class node : public node_impl {
   public:
      //! Constructor.
      node(T t) :
         m_t(std::move(t)) {
      }

      /*! Returns a pointer to the contained T.

      @return
         Pointer to the contained value.
      */
      T * value_ptr() {
         return &m_t;
      }
      T const * value_ptr() const {
         return &m_t;
      }

   public:
      //! Element contained within the node.
      T m_t;
   };

   //! Nodes iterator.
   template <typename TValue>
   class iterator_impl :
      public detail::xor_list_iterator_impl<iterator_impl<TValue>, node, TValue> {
   public:
      //! See detail::xor_list_iterator_impl::xor_list_iterator_impl().
      iterator_impl(node * pnPrev, node * pnCurr, node * pnNext) :
         detail::xor_list_iterator_impl<iterator_impl<TValue>, node, TValue>(
            pnPrev, pnCurr, pnNext
         ) {
      }
   };

public:
   typedef iterator_impl<T> iterator;
   typedef iterator_impl<T const> const_iterator;
   typedef std::reverse_iterator<iterator> reverse_iterator;
   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

public:
   /*! Constructor.

   @param l
      Source object.
   */
   list() {
   }
   list(list && l) :
      detail::list_impl(std::move(l)) {
   }

   //! Destructor.
   ~list() {
      destruct_list(static_cast<node *>(m_pnFirst));
   }

   /*! Assignment operator.

   @param l
      Source object.
   */
   list & operator=(list && l) {
      node * pnFirst = m_pnFirst;
      detail::list_impl::operator=(std::move(l));
      // Now that the *this has been successfully overwritten, destruct the old nodes.
      destruct_list(pnFirst);
      return *this;
   }

   /*! Returns a forward iterator to the start of the list.

   @return
      Iterator to the first node in the list.
   */
   iterator begin() {
      return iterator(nullptr, m_pnFirst, m_pnFirst ? m_pnFirst->get_next(nullptr) : nullptr);
   }

   //! Removes all elements from the list.
   void clear() {
      ABC_TRACE_FUNC(this);

      destruct_list(static_cast<node *>(m_pnFirst));
      m_cNodes = 0;
   }

   /*! Returns a forward iterator to the end of the list.

   @return
      Iterator to the beyond the last node in the list.
   */
   iterator end() {
      return iterator(m_pnLast, nullptr, nullptr);
   }

   /*! Removes and returns the last element in the list.

   @return
      Former last element in the list.
   */
   T pop_back() {
      ABC_TRACE_FUNC(this);

      std::unique_ptr<node> pn(static_cast<node *>(unlink_back()));
      return std::move(pn->m_t);
   }

   /*! Removes the first element in the list.

   @return
      Former first element in the list.
   */
   T pop_front() {
      ABC_TRACE_FUNC(this);

      std::unique_ptr<node> pn(static_cast<node *>(unlink_front()));
      return std::move(pn->m_t);
   }

   /*! Adds an element to the start of the list.

   @param t
      Element to add.
   */
   void push_front(T t) {
      ABC_TRACE_FUNC(this/*, t*/);

      /* Memory management must happen here instead of link_back() because the unique_ptr must be of
      node, since node_impl doesn’t have a virtual destructor. */
      std::unique_ptr<node> pn(new node(std::move(t)));
      link_front(pn.get());
      // No exceptions, so the node is managed as part of the list.
      pn.release();
   }

   /*! Adds an element to the end of the list.

   @param t
      Element to add.
   */
   void push_back(T t) {
      ABC_TRACE_FUNC(this/*, t*/);

      /* Memory management must happen here instead of link_back() because the unique_ptr must be of
      node, since node_impl doesn’t have a virtual destructor. */
      std::unique_ptr<node> pn(new node(std::move(t)));
      link_back(pn.get());
      // No exceptions, so the node is managed as part of the list.
      pn.release();
   }

   /*! Returns a reverse iterator to the end of the list.

   @return
      Reverse Iterator to the last node in the list.
   */
   reverse_iterator rbegin() {
      return reverse_iterator(end());
   }

   //! Removes the last element in the list.
   void remove_back() {
      ABC_TRACE_FUNC(this);

      delete static_cast<node *>(unlink_back());
   }

   //! Removes the first element in the list.
   void remove_front() {
      ABC_TRACE_FUNC(this);

      delete static_cast<node *>(unlink_front());
   }

   /*! Returns a reverse iterator to the start of the list.

   @return
      Reverse iterator to the before the first node in the list.
   */
   reverse_iterator rend() {
      return reverse_iterator(begin());
   }

private:
   /*! Removes all elements from a list, given its first node.

   @param pnFirst
      Pointer to the first node to destruct.
   */
   void destruct_list(node * pnFirst) {
      ABC_TRACE_FUNC(this);

      for (node_impl * pnPrev = nullptr, * pnCurr = pnFirst; pnCurr; ) {
         node_impl * pnNext = pnCurr->get_next(pnPrev);
         delete static_cast<node *>(pnCurr);
         pnPrev = pnCurr;
         pnCurr = pnNext;
      }
      m_cNodes = 0;
   }
};

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef _ABACLADE_LIST_HXX
<commit_msg>Add const versions of abc::list::begin/end/rbegin/rend()<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_LIST_HXX
#define _ABACLADE_LIST_HXX

#ifndef _ABACLADE_HXX
   #error "Please #include <abaclade.hxx> before this file"
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::detail::list_impl

namespace abc {
namespace detail {

//! Non-template implementation class for abc::list.
class ABACLADE_SYM list_impl {
public:
   /*! Constructor.

   @param l
      Source object.
   */
   list_impl() :
      m_pnFirst(nullptr),
      m_pnLast(nullptr),
      m_cNodes(0) {
   }
   list_impl(list_impl && l) :
      m_pnFirst(l.m_pnFirst),
      m_pnLast(l.m_pnLast),
      m_cNodes(l.m_cNodes) {
      l.m_pnFirst = nullptr;
      l.m_pnLast = nullptr;
      l.m_cNodes = 0;
   }

   //! Destructor.
   ~list_impl() {
   }

   /*! Assignment operator.

   @param l
      Source object.
   */
   list_impl & operator=(list_impl && l);

   /*! Returns the count of elements in the list.

   @return
      Count of elements.
   */
   std::size_t size() const {
      return m_cNodes;
   }

protected:
   /*! Inserts a node to the end of the list.

   @param pn
      Pointer to the node to become the first in the list.
   */
   void link_back(xor_list_node_impl * pn);

   /*! Inserts a node to the start of the list.

   @param pn
      Pointer to the node to become the last in the list.
   */
   void link_front(xor_list_node_impl * pn);

   /*! Unlinks and returns the first node in the list.

   @return
      Former first node.
   */
   xor_list_node_impl * unlink_back();

   /*! Unlinks and returns the first node in the list.

   @return
      Former first node.
   */
   xor_list_node_impl * unlink_front();

protected:
   //! Pointer to the first node.
   xor_list_node_impl * m_pnFirst;
   //! Pointer to the last node.
   xor_list_node_impl * m_pnLast;
   //! Count of nodes.
   std::size_t m_cNodes;
};

} //namespace detail
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::list

namespace abc {

//! Doubly-linked list.
template <typename T>
class list : public detail::list_impl {
private:
   typedef detail::xor_list_node_impl node_impl;

protected:
   //! List node.
   class node : public node_impl {
   public:
      //! Constructor.
      node(T t) :
         m_t(std::move(t)) {
      }

      /*! Returns a pointer to the contained T.

      @return
         Pointer to the contained value.
      */
      T * value_ptr() {
         return &m_t;
      }
      T const * value_ptr() const {
         return &m_t;
      }

   public:
      //! Element contained within the node.
      T m_t;
   };

   //! Nodes iterator.
   template <typename TValue>
   class iterator_impl :
      public detail::xor_list_iterator_impl<iterator_impl<TValue>, node, TValue> {
   public:
      //! See detail::xor_list_iterator_impl::xor_list_iterator_impl().
      iterator_impl(node * pnPrev, node * pnCurr, node * pnNext) :
         detail::xor_list_iterator_impl<iterator_impl<TValue>, node, TValue>(
            pnPrev, pnCurr, pnNext
         ) {
      }
   };

public:
   typedef iterator_impl<T> iterator;
   typedef iterator_impl<T const> const_iterator;
   typedef std::reverse_iterator<iterator> reverse_iterator;
   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

public:
   /*! Constructor.

   @param l
      Source object.
   */
   list() {
   }
   list(list && l) :
      detail::list_impl(std::move(l)) {
   }

   //! Destructor.
   ~list() {
      destruct_list(static_cast<node *>(m_pnFirst));
   }

   /*! Assignment operator.

   @param l
      Source object.
   */
   list & operator=(list && l) {
      node * pnFirst = m_pnFirst;
      detail::list_impl::operator=(std::move(l));
      // Now that the *this has been successfully overwritten, destruct the old nodes.
      destruct_list(pnFirst);
      return *this;
   }

   /*! Returns a forward iterator to the start of the list.

   @return
      Iterator to the first node in the list.
   */
   iterator begin() {
      return iterator(nullptr, m_pnFirst, m_pnFirst ? m_pnFirst->get_next(nullptr) : nullptr);
   }
   const_iterator begin() const {
      return const_iterator(nullptr, m_pnFirst, m_pnFirst ? m_pnFirst->get_next(nullptr) : nullptr);
   }

   /*! Returns a const forward iterator to the start of the list.

   @return
      Iterator to the first node in the list.
   */
   const_iterator cbegin() const {
      return const_iterator(nullptr, m_pnFirst, m_pnFirst ? m_pnFirst->get_next(nullptr) : nullptr);
   }

   /*! Returns a const forward iterator to the end of the list.

   @return
      Iterator to the beyond the last node in the list.
   */
   const_iterator cend() const {
      return const_iterator(m_pnLast, nullptr, nullptr);
   }

   //! Removes all elements from the list.
   void clear() {
      ABC_TRACE_FUNC(this);

      destruct_list(static_cast<node *>(m_pnFirst));
      m_cNodes = 0;
   }

   /*! Returns a const reverse iterator to the end of the list.

   @return
      Reverse iterator to the last node in the list.
   */
   const_reverse_iterator crbegin() const {
      return const_reverse_iterator(cend());
   }

   /*! Returns a const reverse iterator to the start of the list.

   @return
      Reverse iterator to the before the first node in the list.
   */
   const_reverse_iterator crend() const {
      return const_reverse_iterator(cbegin());
   }

   /*! Returns a forward iterator to the end of the list.

   @return
      Iterator to the beyond the last node in the list.
   */
   iterator end() {
      return iterator(m_pnLast, nullptr, nullptr);
   }
   const_iterator end() const {
      return const_iterator(m_pnLast, nullptr, nullptr);
   }

   /*! Removes and returns the last element in the list.

   @return
      Former last element in the list.
   */
   T pop_back() {
      ABC_TRACE_FUNC(this);

      std::unique_ptr<node> pn(static_cast<node *>(unlink_back()));
      return std::move(pn->m_t);
   }

   /*! Removes the first element in the list.

   @return
      Former first element in the list.
   */
   T pop_front() {
      ABC_TRACE_FUNC(this);

      std::unique_ptr<node> pn(static_cast<node *>(unlink_front()));
      return std::move(pn->m_t);
   }

   /*! Adds an element to the start of the list.

   @param t
      Element to add.
   */
   void push_front(T t) {
      ABC_TRACE_FUNC(this/*, t*/);

      /* Memory management must happen here instead of link_back() because the unique_ptr must be of
      node, since node_impl doesn’t have a virtual destructor. */
      std::unique_ptr<node> pn(new node(std::move(t)));
      link_front(pn.get());
      // No exceptions, so the node is managed as part of the list.
      pn.release();
   }

   /*! Adds an element to the end of the list.

   @param t
      Element to add.
   */
   void push_back(T t) {
      ABC_TRACE_FUNC(this/*, t*/);

      /* Memory management must happen here instead of link_back() because the unique_ptr must be of
      node, since node_impl doesn’t have a virtual destructor. */
      std::unique_ptr<node> pn(new node(std::move(t)));
      link_back(pn.get());
      // No exceptions, so the node is managed as part of the list.
      pn.release();
   }

   /*! Returns a reverse iterator to the end of the list.

   @return
      Reverse iterator to the last node in the list.
   */
   reverse_iterator rbegin() {
      return reverse_iterator(end());
   }
   const_reverse_iterator rbegin() const {
      return const_reverse_iterator(end());
   }

   //! Removes the last element in the list.
   void remove_back() {
      ABC_TRACE_FUNC(this);

      delete static_cast<node *>(unlink_back());
   }

   //! Removes the first element in the list.
   void remove_front() {
      ABC_TRACE_FUNC(this);

      delete static_cast<node *>(unlink_front());
   }

   /*! Returns a reverse iterator to the start of the list.

   @return
      Reverse iterator to the before the first node in the list.
   */
   reverse_iterator rend() {
      return reverse_iterator(begin());
   }
   const_reverse_iterator rend() const {
      return const_reverse_iterator(begin());
   }

private:
   /*! Removes all elements from a list, given its first node.

   @param pnFirst
      Pointer to the first node to destruct.
   */
   void destruct_list(node * pnFirst) {
      ABC_TRACE_FUNC(this);

      for (node_impl * pnPrev = nullptr, * pnCurr = pnFirst; pnCurr; ) {
         node_impl * pnNext = pnCurr->get_next(pnPrev);
         delete static_cast<node *>(pnCurr);
         pnPrev = pnCurr;
         pnCurr = pnNext;
      }
      m_cNodes = 0;
   }
};

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef _ABACLADE_LIST_HXX
<|endoftext|>


<commit_before>#include <ostream>

namespace ccspec {

// Public methods.

template <typename ConcreteMatcher, typename U>
template <typename V>
bool Matcher<ConcreteMatcher, U>::match(V expected_value) const {
    return static_cast<const ConcreteMatcher*>(this)->match(expected_value);
}

// Protected methods.

template <typename ConcreteMatcher, typename U>
Matcher<ConcreteMatcher, U>::Matcher(U value) : value_(value) {}

template <typename ConcreteMatcher, typename U>
U Matcher<ConcreteMatcher, U>::value() const {
    return value_;
}

template <typename ConcreteMatcher, typename U>
std::ostream& operator<<(std::ostream& stream,
                         const Matcher<ConcreteMatcher, U>& matcher) {
    stream << matcher.toString();
    return stream;
}

} // namespace ccspec
<commit_msg>Add section header comment<commit_after>#include <ostream>

namespace ccspec {

// Public methods.

template <typename ConcreteMatcher, typename U>
template <typename V>
bool Matcher<ConcreteMatcher, U>::match(V expected_value) const {
    return static_cast<const ConcreteMatcher*>(this)->match(expected_value);
}

// Protected methods.

template <typename ConcreteMatcher, typename U>
Matcher<ConcreteMatcher, U>::Matcher(U value) : value_(value) {}

template <typename ConcreteMatcher, typename U>
U Matcher<ConcreteMatcher, U>::value() const {
    return value_;
}

// Operators.

template <typename ConcreteMatcher, typename U>
std::ostream& operator<<(std::ostream& stream,
                         const Matcher<ConcreteMatcher, U>& matcher) {
    stream << matcher.toString();
    return stream;
}

} // namespace ccspec
<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CommonPropertyAccess.cpp Common property access functions
//

// includes
#include "stdafx.h"
#include "CommonPropertyAccess.hpp"

static unsigned int GetUnsignedIntValue(const Variant value)
{
   unsigned int uiValue = 0;

   if (value.Type() == Variant::typeUInt8)
      uiValue = value.Get<unsigned char>();
   else
   if (value.Type() == Variant::typeUInt16)
      uiValue = value.Get<unsigned short>();
   else
   if (value.Type() == Variant::typeUInt32)
      uiValue = value.Get<unsigned int>();
   else
   if (value.Type() == Variant::typeInt32)
      uiValue = static_cast<unsigned int>(value.Get<int>());
   else
      ATLASSERT(false);

   return uiValue;
}

bool FormatValueById(PropIdDisplayInfo* aDispInfo, size_t uiDispInfoSize, unsigned int propertyId, Variant value, CString& cszValue)
{
   for (size_t i=0; i<uiDispInfoSize; i++)
   {
      if (aDispInfo[i].propertyId != propertyId)
         continue;

      const PropIdPossibleValues* possibleValues = aDispInfo[i].possibleValues;

      unsigned int uiValue = GetUnsignedIntValue(value);

      for (size_t j=0; possibleValues[j].pszText != nullptr; j++)
      {
         if (uiValue == possibleValues[j].uiValue)
         {
            cszValue = possibleValues[j].pszText;
            break;
         }
      }

      if (cszValue.IsEmpty())
         cszValue.Format(_T("??? (0x%08x)"), uiValue);

      return true;
   }

   return false;
}

CString FormatApexValue(Variant value)
{
   unsigned int uiAperture = GetUnsignedIntValue(value);

   // special values
   switch(uiAperture)
   {
   case 0x0000: return _T("No lens");
   case 0xffff: return _T("N/A");
   case 0x7fff: return _T("Open");
   case 0x7ffe: return _T("Av max");

      // values that would be calculated wrong by below algorithm
   case 0x25: return _T("f/3.5");
   case 0x33: return _T("f/6.3");
   case 0x43: return _T("f/13");
   }

   if (uiAperture >= 0x08 &&
      uiAperture <= 0x70)
   {
      bool bWithFract = uiAperture <= 0x3c; // 0x3c == f/9.5

      // note: adding 0x10 to value means double aperture
      // exp: 0x08 f/1.0 --> exp = 0
      // exp: 0x18 f/2.0 --> exp = 1
      unsigned int uiExp = (((uiAperture - 8) & 0xf0) / 0x10);

      // 2^0 = f/1, 2^1 = f/2, 2^6 = f/64
      double dAperture = std::pow(2.0, double(uiExp));

      // calc factor from fraction
      double dFactor = 1.0;
      unsigned int uiApertureFract = (uiAperture - 8) & 0x0f;
      switch(uiApertureFract)
      {
      case 0: break;
      case 3: dFactor = 36.0/32.0; break;
      case 4: dFactor = 38.0/32.0; break;
      case 5: dFactor = 40.0/32.0; break;
      case 8: dFactor = 45.0/32.0; break;
      case 11: dFactor = 51.0/32.0; break;
      case 12: dFactor = 54.0/32.0; break;
      case 13: dFactor = 57.0/32.0; break;
      default:
         ATLASSERT(false);
         break;
      }

      dAperture *= dFactor;

      // round after first digit
      dAperture += 0.05;

      unsigned int uiAperture = static_cast<unsigned int>(dAperture);

      CString cszAperture;
      cszAperture.Format(bWithFract ? _T("f/%u.%u") : _T("f/%u"),
         uiAperture,
         static_cast<unsigned int>((dAperture - uiAperture) * 10.0)
      );

      return cszAperture;
   }

   return _T("???");
}

CString FormatShutterSpeedValue(Variant value)
{
   unsigned int uiShutterSpeed = GetUnsignedIntValue(value);

   switch(uiShutterSpeed)
   {
   case 0x04:
   case 0x0c: return _T("Bulb");
   case 0x10: return _T("30\"");
   case 0x13: return _T("25\"");
   case 0x14: return _T("20\"");
   case 0x15: return _T("20\"");
   case 0x18: return _T("15\"");
   case 0x1b: return _T("13\"");
   case 0x1c: return _T("10\"");
   case 0x1d: return _T("10\"");
   case 0x20: return _T("8\"");
   case 0x23: return _T("6\"");
   case 0x24: return _T("6\"");
   case 0x25: return _T("5\"");
   case 0x28: return _T("4\"");
   case 0x2b: return _T("3\"2");
   case 0x2c: return _T("3\"");
   case 0x2d: return _T("2\"5");
   case 0x30: return _T("2\"");
   case 0x33: return _T("1\"6");
   case 0x34: return _T("1\"5");
   case 0x35: return _T("1\"3");
   case 0x38: return _T("1\"");
   case 0x3b: return _T("0\"8");
   case 0x3c: return _T("0\"7");
   case 0x3d: return _T("0\"6");
   case 0x40: return _T("0\"5");
   case 0x43: return _T("0\"4");
   case 0x44: return _T("0\"3");
   case 0x45: return _T("0\"3");
   case 0x48: return _T("1/4");
   case 0x4b: return _T("1/5");
   case 0x4c: return _T("1/6");
   case 0x4d: return _T("1/6");
   case 0x50: return _T("1/8");
   case 0x53: return _T("1/10");
   case 0x54: return _T("1/10");
   case 0x55: return _T("1/13");
   case 0x58: return _T("1/15");
   case 0x5b: return _T("1/20");
   case 0x5c: return _T("1/20");
   case 0x5d: return _T("1/25");
   case 0x60: return _T("1/30");
   case 0x63: return _T("1/40");
   case 0x64: return _T("1/45");
   case 0x65: return _T("1/50");
   case 0x68: return _T("1/60");
   case 0x6b: return _T("1/80");
   case 0x6c: return _T("1/90");
   case 0x6d: return _T("1/100");
   case 0x70: return _T("1/125");
   case 0x73: return _T("1/160");
   case 0x74: return _T("1/180");
   case 0x75: return _T("1/200");
   case 0x78: return _T("1/250");
   case 0x7b: return _T("1/320");
   case 0x7c: return _T("1/350");
   case 0x7d: return _T("1/400");
   case 0x80: return _T("1/500");
   case 0x83: return _T("1/640");
   case 0x84: return _T("1/750");
   case 0x85: return _T("1/800");
   case 0x88: return _T("1/1000");
   case 0x8b: return _T("1/1250");
   case 0x8c: return _T("1/1500");
   case 0x8d: return _T("1/1600");
   case 0x90: return _T("1/2000");
   case 0x93: return _T("1/2500");
   case 0x94: return _T("1/3000");
   case 0x95: return _T("1/3200");
   case 0x98: return _T("1/4000");
   case 0x9b: return _T("1/5000");
   case 0x9c: return _T("1/6000");
   case 0x9d: return _T("1/64000");
   case 0xa0: return _T("1/8000");
   case 0xffff: return _T("N/A");

   default:
      ATLASSERT(false);
      break;
   }

   return _T("???");
}

CString FormatIsoValue(Variant value)
{
   unsigned int uiIso = GetUnsignedIntValue(value);

   switch(uiIso)
   {
   case 0x00: return _T("Auto");
   case 0x28: return _T("6");
   case 0x30: return _T("12");
   case 0x38: return _T("25");
   case 0x43: return _T("64");
   case 0x45: return _T("80");
   case 0xffff:
   case 0xffffffff:
      return _T("Invalid");
   default:
      if (uiIso >= 0x48 && uiIso <= 0x78)
      {
         ATLASSERT((uiIso & 7) == 0); // must be divisable by 8

         unsigned int uiIsoValue = 100;
         unsigned int uiFactor = ((uiIso - 0x48) / 8);
         uiIsoValue *= 1 << uiFactor;

         CString cszValue;
         cszValue.Format(_T("%u"), uiIsoValue);
         return cszValue;
      }
      ATLASSERT(false);
      break;
   }

   return _T("???");
}

CString FormatCompensationValue(Variant value, bool bIsEdsdk)
{
   // PSREC: +3 EV .. -3 EV <=> 0x00 .. 0x30
   // CDSDK: +3 EV .. -3 EV <=> 0x00 .. 0x30
   // EDSDK: +3 EV .. -3 EV <=> 0x18 .. 0x00, 0xff .. 0xe8
   // PSREC is the same as CDSDK
   // EDSDK = 0x18 - CDSDK

   unsigned int uiComp = GetUnsignedIntValue(value);

   int iValue = bIsEdsdk ? int(char(uiComp)) : 0x18 - int(uiComp);
   if (iValue == 0)
      return _T("0");

   int iFract = std::abs(iValue) & 7; // first 3 bits
   int iInt = std::abs(iValue) / 8;

   CString cszFract =
      iFract == 4 ? _T("1/2") :
      iFract == 3 ? _T("1/3") :
      iFract == 5 ? _T("2/3") : _T("???");

   TCHAR cSign = iValue < 0 ? _T('-') : _T('+');

   CString cszValue;

   if (iInt == 0)
      cszValue.Format(_T("%c%s"), cSign, cszFract.GetString());
   else
   {
      cszValue.Format(
         iFract == 0 ? _T("%c%u") : _T("%c%u (%s)"),
         cSign,
         iInt,
         cszFract);
   }

   return cszValue;
}
<commit_msg>fixed local function GetUnsignedIntValue()<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CommonPropertyAccess.cpp Common property access functions
//

// includes
#include "stdafx.h"
#include "CommonPropertyAccess.hpp"

/// returns unsigned integer value from variant
static unsigned int GetUnsignedIntValue(const Variant& value)
{
   unsigned int uiValue = 0;

   if (value.Type() == Variant::typeUInt8)
      uiValue = value.Get<unsigned char>();
   else
   if (value.Type() == Variant::typeUInt16)
      uiValue = value.Get<unsigned short>();
   else
   if (value.Type() == Variant::typeUInt32)
      uiValue = value.Get<unsigned int>();
   else
   if (value.Type() == Variant::typeInt32)
      uiValue = static_cast<unsigned int>(value.Get<int>());
   else
      ATLASSERT(false);

   return uiValue;
}

bool FormatValueById(PropIdDisplayInfo* aDispInfo, size_t uiDispInfoSize, unsigned int propertyId, Variant value, CString& cszValue)
{
   for (size_t i=0; i<uiDispInfoSize; i++)
   {
      if (aDispInfo[i].propertyId != propertyId)
         continue;

      const PropIdPossibleValues* possibleValues = aDispInfo[i].possibleValues;

      unsigned int uiValue = GetUnsignedIntValue(value);

      for (size_t j=0; possibleValues[j].pszText != nullptr; j++)
      {
         if (uiValue == possibleValues[j].uiValue)
         {
            cszValue = possibleValues[j].pszText;
            break;
         }
      }

      if (cszValue.IsEmpty())
         cszValue.Format(_T("??? (0x%08x)"), uiValue);

      return true;
   }

   return false;
}

CString FormatApexValue(Variant value)
{
   unsigned int uiAperture = GetUnsignedIntValue(value);

   // special values
   switch(uiAperture)
   {
   case 0x0000: return _T("No lens");
   case 0xffff: return _T("N/A");
   case 0x7fff: return _T("Open");
   case 0x7ffe: return _T("Av max");

      // values that would be calculated wrong by below algorithm
   case 0x25: return _T("f/3.5");
   case 0x33: return _T("f/6.3");
   case 0x43: return _T("f/13");
   }

   if (uiAperture >= 0x08 &&
      uiAperture <= 0x70)
   {
      bool bWithFract = uiAperture <= 0x3c; // 0x3c == f/9.5

      // note: adding 0x10 to value means double aperture
      // exp: 0x08 f/1.0 --> exp = 0
      // exp: 0x18 f/2.0 --> exp = 1
      unsigned int uiExp = (((uiAperture - 8) & 0xf0) / 0x10);

      // 2^0 = f/1, 2^1 = f/2, 2^6 = f/64
      double dAperture = std::pow(2.0, double(uiExp));

      // calc factor from fraction
      double dFactor = 1.0;
      unsigned int uiApertureFract = (uiAperture - 8) & 0x0f;
      switch(uiApertureFract)
      {
      case 0: break;
      case 3: dFactor = 36.0/32.0; break;
      case 4: dFactor = 38.0/32.0; break;
      case 5: dFactor = 40.0/32.0; break;
      case 8: dFactor = 45.0/32.0; break;
      case 11: dFactor = 51.0/32.0; break;
      case 12: dFactor = 54.0/32.0; break;
      case 13: dFactor = 57.0/32.0; break;
      default:
         ATLASSERT(false);
         break;
      }

      dAperture *= dFactor;

      // round after first digit
      dAperture += 0.05;

      unsigned int uiAperture = static_cast<unsigned int>(dAperture);

      CString cszAperture;
      cszAperture.Format(bWithFract ? _T("f/%u.%u") : _T("f/%u"),
         uiAperture,
         static_cast<unsigned int>((dAperture - uiAperture) * 10.0)
      );

      return cszAperture;
   }

   return _T("???");
}

CString FormatShutterSpeedValue(Variant value)
{
   unsigned int uiShutterSpeed = GetUnsignedIntValue(value);

   switch(uiShutterSpeed)
   {
   case 0x04:
   case 0x0c: return _T("Bulb");
   case 0x10: return _T("30\"");
   case 0x13: return _T("25\"");
   case 0x14: return _T("20\"");
   case 0x15: return _T("20\"");
   case 0x18: return _T("15\"");
   case 0x1b: return _T("13\"");
   case 0x1c: return _T("10\"");
   case 0x1d: return _T("10\"");
   case 0x20: return _T("8\"");
   case 0x23: return _T("6\"");
   case 0x24: return _T("6\"");
   case 0x25: return _T("5\"");
   case 0x28: return _T("4\"");
   case 0x2b: return _T("3\"2");
   case 0x2c: return _T("3\"");
   case 0x2d: return _T("2\"5");
   case 0x30: return _T("2\"");
   case 0x33: return _T("1\"6");
   case 0x34: return _T("1\"5");
   case 0x35: return _T("1\"3");
   case 0x38: return _T("1\"");
   case 0x3b: return _T("0\"8");
   case 0x3c: return _T("0\"7");
   case 0x3d: return _T("0\"6");
   case 0x40: return _T("0\"5");
   case 0x43: return _T("0\"4");
   case 0x44: return _T("0\"3");
   case 0x45: return _T("0\"3");
   case 0x48: return _T("1/4");
   case 0x4b: return _T("1/5");
   case 0x4c: return _T("1/6");
   case 0x4d: return _T("1/6");
   case 0x50: return _T("1/8");
   case 0x53: return _T("1/10");
   case 0x54: return _T("1/10");
   case 0x55: return _T("1/13");
   case 0x58: return _T("1/15");
   case 0x5b: return _T("1/20");
   case 0x5c: return _T("1/20");
   case 0x5d: return _T("1/25");
   case 0x60: return _T("1/30");
   case 0x63: return _T("1/40");
   case 0x64: return _T("1/45");
   case 0x65: return _T("1/50");
   case 0x68: return _T("1/60");
   case 0x6b: return _T("1/80");
   case 0x6c: return _T("1/90");
   case 0x6d: return _T("1/100");
   case 0x70: return _T("1/125");
   case 0x73: return _T("1/160");
   case 0x74: return _T("1/180");
   case 0x75: return _T("1/200");
   case 0x78: return _T("1/250");
   case 0x7b: return _T("1/320");
   case 0x7c: return _T("1/350");
   case 0x7d: return _T("1/400");
   case 0x80: return _T("1/500");
   case 0x83: return _T("1/640");
   case 0x84: return _T("1/750");
   case 0x85: return _T("1/800");
   case 0x88: return _T("1/1000");
   case 0x8b: return _T("1/1250");
   case 0x8c: return _T("1/1500");
   case 0x8d: return _T("1/1600");
   case 0x90: return _T("1/2000");
   case 0x93: return _T("1/2500");
   case 0x94: return _T("1/3000");
   case 0x95: return _T("1/3200");
   case 0x98: return _T("1/4000");
   case 0x9b: return _T("1/5000");
   case 0x9c: return _T("1/6000");
   case 0x9d: return _T("1/64000");
   case 0xa0: return _T("1/8000");
   case 0xffff: return _T("N/A");

   default:
      ATLASSERT(false);
      break;
   }

   return _T("???");
}

CString FormatIsoValue(Variant value)
{
   unsigned int uiIso = GetUnsignedIntValue(value);

   switch(uiIso)
   {
   case 0x00: return _T("Auto");
   case 0x28: return _T("6");
   case 0x30: return _T("12");
   case 0x38: return _T("25");
   case 0x43: return _T("64");
   case 0x45: return _T("80");
   case 0xffff:
   case 0xffffffff:
      return _T("Invalid");
   default:
      if (uiIso >= 0x48 && uiIso <= 0x78)
      {
         ATLASSERT((uiIso & 7) == 0); // must be divisable by 8

         unsigned int uiIsoValue = 100;
         unsigned int uiFactor = ((uiIso - 0x48) / 8);
         uiIsoValue *= 1 << uiFactor;

         CString cszValue;
         cszValue.Format(_T("%u"), uiIsoValue);
         return cszValue;
      }
      ATLASSERT(false);
      break;
   }

   return _T("???");
}

CString FormatCompensationValue(Variant value, bool bIsEdsdk)
{
   // PSREC: +3 EV .. -3 EV <=> 0x00 .. 0x30
   // CDSDK: +3 EV .. -3 EV <=> 0x00 .. 0x30
   // EDSDK: +3 EV .. -3 EV <=> 0x18 .. 0x00, 0xff .. 0xe8
   // PSREC is the same as CDSDK
   // EDSDK = 0x18 - CDSDK

   unsigned int uiComp = GetUnsignedIntValue(value);

   int iValue = bIsEdsdk ? int(char(uiComp)) : 0x18 - int(uiComp);
   if (iValue == 0)
      return _T("0");

   int iFract = std::abs(iValue) & 7; // first 3 bits
   int iInt = std::abs(iValue) / 8;

   CString cszFract =
      iFract == 4 ? _T("1/2") :
      iFract == 3 ? _T("1/3") :
      iFract == 5 ? _T("2/3") : _T("???");

   TCHAR cSign = iValue < 0 ? _T('-') : _T('+');

   CString cszValue;

   if (iInt == 0)
      cszValue.Format(_T("%c%s"), cSign, cszFract.GetString());
   else
   {
      cszValue.Format(
         iFract == 0 ? _T("%c%u") : _T("%c%u (%s)"),
         cSign,
         iInt,
         cszFract);
   }

   return cszValue;
}
<|endoftext|>


<commit_before>
#include <cstdint>
#include <string>

#pragma once

// Define the data types
typedef uint8_t inputDataType;
std::string inputDataName("uchar");
typedef float intermediateDataType;
std::string intermediateDataName("float");
typedef float outputDataType;
std::string outputDataName("float");

<commit_msg>Style fix.<commit_after>
#include <cstdint>
#include <string>

#pragma once

// Define the data types
typedef uint8_t inputDataType;
std::string inputDataName("uchar");
typedef float intermediateDataType;
std::string intermediateDataName("float");
typedef float outputDataType;
std::string outputDataName("float");

<|endoftext|>


<commit_before>// Copyright 2021 Global Phasing Ltd.
//
// A class for converting SF-mmCIF to MTZ (merged or unmerged).

#ifndef GEMMI_CIF2MTZ_HPP_
#define GEMMI_CIF2MTZ_HPP_

#include <ostream>
#include <map>
#include <set>
#include <utility>
#include "cifdoc.hpp"   // for Loop, as_int, ...
#include "fail.hpp"     // for fail
#include "mtz.hpp"      // for Mtz
#include "numb.hpp"     // for as_number
#include "refln.hpp"    // for ReflnBlock
#include "version.hpp"  // for GEMMI_VERSION

namespace gemmi {

struct CifToMtz {
  static const char** default_spec(bool for_merged) {
    static const char* merged[] = {
      "pdbx_r_free_flag FreeR_flag I 0",
      "status FreeR_flag s 0", // s is a special flag
      "intensity_meas IMEAN J 1",
      "intensity_sigma SIGIMEAN Q 1",
      "pdbx_I_plus I(+) K 1",
      "pdbx_I_plus_sigma SIGI(+) M 1",
      "pdbx_I_minus I(-) K 1",
      "pdbx_I_minus_sigma SIGI(-) M 1",
      "F_meas FP F 1",
      "F_meas_au FP F 1",
      "F_meas_sigma SIGFP Q 1",
      "F_meas_sigma_au SIGFP Q 1",
      "pdbx_F_plus F(+) G 1",
      "pdbx_F_plus_sigma SIGF(+) L 1",
      "pdbx_F_minus F(-) G 1",
      "pdbx_F_minus_sigma SIGF(-) L 1",
      "pdbx_anom_difference DP D 1",
      "pdbx_anom_difference_sigma SIGDP Q 1",
      "F_calc FC F 1",
      "F_calc_au FC F 1",
      "phase_calc PHIC P 1",
      "fom FOM W 1",
      "weight FOM W 1",
      "pdbx_HL_A_iso HLA A 1",
      "pdbx_HL_B_iso HLB A 1",
      "pdbx_HL_C_iso HLC A 1",
      "pdbx_HL_D_iso HLD A 1",
      "pdbx_FWT FWT F 1",
      "pdbx_PHWT PHWT P 1",
      "pdbx_DELFWT DELFWT F 1",
      "pdbx_DELPHWT DELPHWT P 1",
      nullptr
    };
    static const char* unmerged[] = {
      "intensity_meas I J 0",  // for unmerged data is category refln
      "intensity_net I J 0",
      "intensity_sigma SIGI Q 0",
      "pdbx_detector_x XDET R 0",
      "pdbx_detector_y YDET R 0",
      "pdbx_scan_angle ROT R 0",
      nullptr
    };
    return for_merged ? merged : unmerged;
  };

  struct Entry {
    std::string refln_tag;
    std::string col_label;
    char col_type;
    int dataset_id;

    Entry(const std::string& line) {
      std::vector<std::string> tokens;
      tokens.reserve(4);
      split_str_into_multi(line, " \t\r\n", tokens);
      if (tokens.size() != 4)
        fail("line should have 4 words: " + line);
      if (tokens[2].size() != 1 || tokens[3].size() != 1 ||
          (tokens[3][0] != '0' && tokens[3][0] != '1'))
        fail("incorrect line: " + line);
      refln_tag = tokens[0];
      col_label = tokens[1];
      col_type = tokens[2][0];
      dataset_id = tokens[3][0] - '0';
    }
  };

  // Alternative mmCIF tags for the same MTZ label should be consecutive
  bool verbose = false;
  bool force_unmerged = false;
  std::string title;
  std::vector<std::string> history = { "From gemmi-cif2mtz " GEMMI_VERSION };
  std::vector<std::string> spec_lines;

  Mtz convert_block_to_mtz(const ReflnBlock& rb, std::ostream& out) const {
    Mtz mtz;
    mtz.title = title.empty() ? "Converted from mmCIF block " + rb.block.name : title;
    if (!history.empty()) {
      mtz.history.reserve(mtz.history.size() + history.size());
      mtz.history.insert(mtz.history.end(), history.begin(), history.end());
    }
    mtz.cell = rb.cell;
    mtz.spacegroup = rb.spacegroup;
    mtz.add_dataset("HKL_base");
    mtz.add_dataset("unknown").wavelength = rb.wavelength;
    const cif::Loop* loop = rb.refln_loop ? rb.refln_loop : rb.diffrn_refln_loop;
    if (!loop)
      fail("_refln category not found in mmCIF block: " + rb.block.name);
    if (verbose)
      out << "Searching tags with known MTZ equivalents ...\n";
    bool uses_status = false;
    std::vector<int> indices;
    std::string tag = loop->tags[0];
    const size_t len = tag.find('.') + 1;

    bool unmerged = force_unmerged || !rb.refln_loop;

    std::vector<Entry> spec_entries;
    if (!spec_lines.empty()) {
      spec_entries.reserve(spec_lines.size());
      for (const std::string& line : spec_lines)
        spec_entries.emplace_back(line);
    } else {
      const char** line = default_spec(!unmerged);
      for (; *line != nullptr; ++line)
        spec_entries.emplace_back(*line);
    }

    // always start with H, K, L
    tag.replace(len, std::string::npos, "index_h");
    for (char c : {'h', 'k', 'l'}) {
      tag.back() = c;
      int index = loop->find_tag(tag);
      if (index == -1)
        fail("Miller index tag not found: " + tag);
      indices.push_back(index);
      auto col = mtz.columns.emplace(mtz.columns.end());
      col->dataset_id = 0;
      col->type = 'H';
      col->label = alpha_up(c);
    }

    // M/ISYM and BATCH
    if (unmerged) {
      auto col = mtz.columns.emplace(mtz.columns.end());
      col->dataset_id = 0;
      col->type = 'Y';
      col->label = "M/ISYM";

      col = mtz.columns.emplace(mtz.columns.end());
      col->dataset_id = 0;
      col->type = 'B';
      col->label = "BATCH";
    }

    // other columns according to the spec
    bool column_added = false;
    for (const Entry& entry : spec_entries) {
      tag.replace(len, std::string::npos, entry.refln_tag);
      int index = loop->find_tag(tag);
      if (index == -1)
        continue;
      if (mtz.column_with_label(entry.col_label))
        continue;
      column_added = true;
      indices.push_back(index);
      auto col = mtz.columns.emplace(mtz.columns.end());
      // dataset_id is meaningless in unmerged MTZ files
      col->dataset_id = unmerged ? 0 : entry.dataset_id;
      col->type = entry.col_type;
      if (col->type == 's') {
        col->type = 'I';
        uses_status = true;
      }
      col->label = entry.col_label;
      if (verbose)
        out << "  " << tag << " -> " << col->label << '\n';
    }
    if (!column_added)
      fail(force_unmerged ? "Unmerged d" : "D", "ata not found in block ", rb.block.name);

    for (size_t i = 0; i != mtz.columns.size(); ++i) {
      mtz.columns[i].parent = &mtz;
      mtz.columns[i].idx = i;
    }
    mtz.nreflections = (int) loop->length();

    std::unique_ptr<UnmergedHklMover> hkl_mover;
    struct BatchInfo {
      int sweep_id;
      int frame_id;
    };
    std::vector<BatchInfo> batch_nums;
    if (unmerged) {
      hkl_mover.reset(new UnmergedHklMover(mtz.spacegroup));
      tag.replace(len, std::string::npos, "diffrn_id");
      int sweep_id_index = loop->find_tag(tag);
      tag.replace(len, std::string::npos, "pdbx_image_id");
      int image_id_index = loop->find_tag(tag);
      if (sweep_id_index == -1 || image_id_index == -1) {
        if (verbose)
          out << "No pdbx_image_id, setting BATCH to a dummy value.\n";
        auto batch = mtz.batches.emplace(mtz.batches.end());
        batch->number = 1;
        batch->set_dataset_id(1);
        batch->set_cell(mtz.cell);
        // FIXME should we set more properties in BATCH header?
      } else {
        if (verbose)
          out << "  " << tag << " & diffrn_id -> BATCH\n";
        struct SweepInfo {
          std::set<int> frame_ids;
          int offset;
          float wavelength = 0.f;
        };
        std::map<int, SweepInfo> sweeps;
        cif::Block& block = const_cast<cif::Block&>(rb.block);
        cif::Table tab_w1 = block.find("_diffrn_radiation.",
                                       {"diffrn_id", "wavelength_id"});
        cif::Table tab_w2 = block.find("_diffrn_radiation_wavelength.",
                                       {"id", "wavelength"});
        // store sweep and frame numbers corresponding to reflections
        batch_nums.reserve(loop->length());
        for (size_t i = 0; i < loop->values.size(); i += loop->tags.size()) {
          const std::string& sweep_str = loop->values[i + sweep_id_index];
          int sweep_id = cif::as_int(sweep_str, 0);
          const std::string& frame_str = loop->values[i + image_id_index];
          int frame = 1;
          if (!cif::is_null(frame_str))
            frame = (int) std::ceil(cif::as_number(frame_str));
          batch_nums.push_back({sweep_id, frame});
          if (frame >= 0) {
            SweepInfo& sweep = sweeps[sweep_id];
            if (sweep.frame_ids.empty()) {
              try {
                const std::string& wave_id = tab_w1.find_row(sweep_str)[1];
                const std::string& wavelen = tab_w2.find_row(wave_id)[1];
                sweep.wavelength = (float) cif::as_number(wavelen, 0.);
              } catch(std::exception&) {}
            }
            sweep.frame_ids.insert(frame);
          }
        }

        // determine offset (that makes frame numbers unique) and wavelength
        int cap = 0;
        for (auto& it : sweeps) {
          it.second.offset = cap;
          cap += *--it.second.frame_ids.end() + 1100;
          cap -= cap % 1000;
        }
        // add offset to BatchInfo::frame_id
        for (BatchInfo& p : batch_nums)
          if (p.sweep_id >= 0 && p.frame_id >= 0)
            p.frame_id += sweeps.at(p.sweep_id).offset;

        for (const auto& sweep_pair : sweeps) {
          const SweepInfo& sweep_info = sweep_pair.second;
          Mtz::Batch batch;
          // Should we have separate mtz dataset (batch-set) for each diffrn_id?
          batch.set_dataset_id(1);  // alternatively, use sweep_pair.first
          batch.set_cell(mtz.cell);
          batch.set_wavelength(sweep_info.wavelength);
          int min_frame = *sweep_info.frame_ids.begin();
          int max_frame = *--sweep_info.frame_ids.end();
          if (2 * sweep_info.frame_ids.size() > size_t(max_frame - min_frame)) {
            // probably consecutive range, even if some frames are missing
            for (int n = min_frame; n <= max_frame; ++n) {
              batch.number = n + sweep_info.offset;
              mtz.batches.push_back(batch);
            }
          } else {
            for (int n : sweep_info.frame_ids) {
              batch.number = n + sweep_info.offset;
              mtz.batches.push_back(batch);
            }
          }
        }
      }
    }

    // fill in the data
    mtz.data.resize(mtz.columns.size() * mtz.nreflections);
    size_t k = 0, row = 0;
    for (size_t i = 0; i < loop->values.size(); i += loop->tags.size()) {
      if (unmerged) {
        std::array<int, 3> hkl;
        for (int ii = 0; ii != 3; ++ii)
          hkl[ii] = cif::as_int(loop->values[i + indices[ii]]);
        int isym = hkl_mover->move_to_asu(hkl);
        for (int j = 0; j != 3; ++j)
          mtz.data[k++] = (float) hkl[j];
        mtz.data[k++] = (float) isym;
        mtz.data[k++] = batch_nums.empty() ? 1.f : (float) batch_nums[row++].frame_id;
      } else {
        for (int j = 0; j != 3; ++j)
          mtz.data[k++] = (float) cif::as_int(loop->values[i + indices[j]]);
      }
      size_t j = 3;
      if (uses_status)
        mtz.data[k++] = status_to_freeflag(loop->values[i + indices[j++]]);
      for (; j != indices.size(); ++j) {
        const std::string& v = loop->values[i + indices[j]];
        if (cif::is_null(v)) {
          mtz.data[k] = (float) NAN;
        } else {
          mtz.data[k] = (float) cif::as_number(v);
          if (std::isnan(mtz.data[k]))
            out << "Value #" << i + indices[j] << " in the loop is not a number: "
                << v << '\n';
        }
        ++k;
      }
    }
    return mtz;
  }

private:
  static float status_to_freeflag(const std::string& str) {
    char c = str[0];
    if (c == '\'' || c == '"')
      c = str[1];
    if (c == 'o')
      return 1.f;
    if (c == 'f')
      return 0.f;
    return NAN;
  }
};

} // namespace gemmi
#endif
<commit_msg>cif2mtz: read crystal_id and set Datasets correspondingly<commit_after>// Copyright 2021 Global Phasing Ltd.
//
// A class for converting SF-mmCIF to MTZ (merged or unmerged).

#ifndef GEMMI_CIF2MTZ_HPP_
#define GEMMI_CIF2MTZ_HPP_

#include <ostream>
#include <map>
#include <set>
#include <utility>
#include "cifdoc.hpp"   // for Loop, as_int, ...
#include "fail.hpp"     // for fail
#include "mtz.hpp"      // for Mtz
#include "numb.hpp"     // for as_number
#include "refln.hpp"    // for ReflnBlock
#include "version.hpp"  // for GEMMI_VERSION

namespace gemmi {

struct CifToMtz {
  static const char** default_spec(bool for_merged) {
    static const char* merged[] = {
      "pdbx_r_free_flag FreeR_flag I 0",
      "status FreeR_flag s 0", // s is a special flag
      "intensity_meas IMEAN J 1",
      "intensity_sigma SIGIMEAN Q 1",
      "pdbx_I_plus I(+) K 1",
      "pdbx_I_plus_sigma SIGI(+) M 1",
      "pdbx_I_minus I(-) K 1",
      "pdbx_I_minus_sigma SIGI(-) M 1",
      "F_meas FP F 1",
      "F_meas_au FP F 1",
      "F_meas_sigma SIGFP Q 1",
      "F_meas_sigma_au SIGFP Q 1",
      "pdbx_F_plus F(+) G 1",
      "pdbx_F_plus_sigma SIGF(+) L 1",
      "pdbx_F_minus F(-) G 1",
      "pdbx_F_minus_sigma SIGF(-) L 1",
      "pdbx_anom_difference DP D 1",
      "pdbx_anom_difference_sigma SIGDP Q 1",
      "F_calc FC F 1",
      "F_calc_au FC F 1",
      "phase_calc PHIC P 1",
      "fom FOM W 1",
      "weight FOM W 1",
      "pdbx_HL_A_iso HLA A 1",
      "pdbx_HL_B_iso HLB A 1",
      "pdbx_HL_C_iso HLC A 1",
      "pdbx_HL_D_iso HLD A 1",
      "pdbx_FWT FWT F 1",
      "pdbx_PHWT PHWT P 1",
      "pdbx_DELFWT DELFWT F 1",
      "pdbx_DELPHWT DELPHWT P 1",
      nullptr
    };
    static const char* unmerged[] = {
      "intensity_meas I J 0",  // for unmerged data is category refln
      "intensity_net I J 0",
      "intensity_sigma SIGI Q 0",
      "pdbx_detector_x XDET R 0",
      "pdbx_detector_y YDET R 0",
      "pdbx_scan_angle ROT R 0",
      nullptr
    };
    return for_merged ? merged : unmerged;
  };

  struct Entry {
    std::string refln_tag;
    std::string col_label;
    char col_type;
    int dataset_id;

    Entry(const std::string& line) {
      std::vector<std::string> tokens;
      tokens.reserve(4);
      split_str_into_multi(line, " \t\r\n", tokens);
      if (tokens.size() != 4)
        fail("line should have 4 words: " + line);
      if (tokens[2].size() != 1 || tokens[3].size() != 1 ||
          (tokens[3][0] != '0' && tokens[3][0] != '1'))
        fail("incorrect line: " + line);
      refln_tag = tokens[0];
      col_label = tokens[1];
      col_type = tokens[2][0];
      dataset_id = tokens[3][0] - '0';
    }
  };

  // Alternative mmCIF tags for the same MTZ label should be consecutive
  bool verbose = false;
  bool force_unmerged = false;
  std::string title;
  std::vector<std::string> history = { "From gemmi-cif2mtz " GEMMI_VERSION };
  std::vector<std::string> spec_lines;

  Mtz convert_block_to_mtz(const ReflnBlock& rb, std::ostream& out) const {
    Mtz mtz;
    mtz.title = title.empty() ? "Converted from mmCIF block " + rb.block.name : title;
    if (!history.empty()) {
      mtz.history.reserve(mtz.history.size() + history.size());
      mtz.history.insert(mtz.history.end(), history.begin(), history.end());
    }
    mtz.cell = rb.cell;
    mtz.spacegroup = rb.spacegroup;
    mtz.add_dataset("HKL_base");
    const cif::Loop* loop = rb.refln_loop ? rb.refln_loop : rb.diffrn_refln_loop;
    if (!loop)
      fail("_refln category not found in mmCIF block: " + rb.block.name);
    if (verbose)
      out << "Searching tags with known MTZ equivalents ...\n";
    bool uses_status = false;
    std::vector<int> indices;
    std::string tag = loop->tags[0];
    const size_t len = tag.find('.') + 1;

    bool unmerged = force_unmerged || !rb.refln_loop;

    std::vector<Entry> spec_entries;
    if (!spec_lines.empty()) {
      spec_entries.reserve(spec_lines.size());
      for (const std::string& line : spec_lines)
        spec_entries.emplace_back(line);
    } else {
      const char** line = default_spec(!unmerged);
      for (; *line != nullptr; ++line)
        spec_entries.emplace_back(*line);
    }

    // always start with H, K, L
    tag.replace(len, std::string::npos, "index_h");
    for (char c : {'h', 'k', 'l'}) {
      tag.back() = c;
      int index = loop->find_tag(tag);
      if (index == -1)
        fail("Miller index tag not found: " + tag);
      indices.push_back(index);
      auto col = mtz.columns.emplace(mtz.columns.end());
      col->dataset_id = 0;
      col->type = 'H';
      col->label = alpha_up(c);
    }

    // M/ISYM and BATCH
    if (unmerged) {
      auto col = mtz.columns.emplace(mtz.columns.end());
      col->dataset_id = 0;
      col->type = 'Y';
      col->label = "M/ISYM";

      col = mtz.columns.emplace(mtz.columns.end());
      col->dataset_id = 0;
      col->type = 'B';
      col->label = "BATCH";
    }

    if (!unmerged)
      mtz.add_dataset("unknown").wavelength = rb.wavelength;

    // other columns according to the spec
    bool column_added = false;
    for (const Entry& entry : spec_entries) {
      tag.replace(len, std::string::npos, entry.refln_tag);
      int index = loop->find_tag(tag);
      if (index == -1)
        continue;
      if (mtz.column_with_label(entry.col_label))
        continue;
      column_added = true;
      indices.push_back(index);
      auto col = mtz.columns.emplace(mtz.columns.end());
      // dataset_id is meaningless in unmerged MTZ files
      col->dataset_id = unmerged ? 0 : entry.dataset_id;
      col->type = entry.col_type;
      if (col->type == 's') {
        col->type = 'I';
        uses_status = true;
      }
      col->label = entry.col_label;
      if (verbose)
        out << "  " << tag << " -> " << col->label << '\n';
    }
    if (!column_added)
      fail(force_unmerged ? "Unmerged d" : "D", "ata not found in block ", rb.block.name);

    for (size_t i = 0; i != mtz.columns.size(); ++i) {
      mtz.columns[i].parent = &mtz;
      mtz.columns[i].idx = i;
    }
    mtz.nreflections = (int) loop->length();

    std::unique_ptr<UnmergedHklMover> hkl_mover;
    struct BatchInfo {
      int sweep_id;
      int frame_id;
    };
    std::vector<BatchInfo> batch_nums;
    if (unmerged) {
      hkl_mover.reset(new UnmergedHklMover(mtz.spacegroup));
      tag.replace(len, std::string::npos, "diffrn_id");
      int sweep_id_index = loop->find_tag(tag);
      tag.replace(len, std::string::npos, "pdbx_image_id");
      int image_id_index = loop->find_tag(tag);
      if (sweep_id_index == -1 || image_id_index == -1) {
        if (verbose)
          out << "No pdbx_image_id, setting BATCH to a dummy value.\n";
        auto batch = mtz.batches.emplace(mtz.batches.end());
        batch->number = 1;
        batch->set_dataset_id(1);
        batch->set_cell(mtz.cell);
        // FIXME should we set more properties in BATCH header?
      } else {
        if (verbose)
          out << "  " << tag << " & diffrn_id -> BATCH\n";
        struct SweepInfo {
          std::set<int> frame_ids;
          int offset;
          float wavelength = 0.f;
          std::string crystal_id;
          int dataset_id;
        };
        std::map<int, SweepInfo> sweeps;
        cif::Block& block = const_cast<cif::Block&>(rb.block);
        cif::Table tab_w0 = block.find("_diffrn.", {"id", "crystal_id"});
        cif::Table tab_w1 = block.find("_diffrn_radiation.",
                                       {"diffrn_id", "wavelength_id"});
        cif::Table tab_w2 = block.find("_diffrn_radiation_wavelength.",
                                       {"id", "wavelength"});
        // store sweep and frame numbers corresponding to reflections
        batch_nums.reserve(loop->length());
        for (size_t i = 0; i < loop->values.size(); i += loop->tags.size()) {
          const std::string& sweep_str = loop->values[i + sweep_id_index];
          int sweep_id = cif::as_int(sweep_str, 0);
          const std::string& frame_str = loop->values[i + image_id_index];
          int frame = 1;
          if (!cif::is_null(frame_str))
            frame = (int) std::ceil(cif::as_number(frame_str));
          batch_nums.push_back({sweep_id, frame});
          if (frame >= 0) {
            SweepInfo& sweep = sweeps[sweep_id];
            if (sweep.frame_ids.empty()) {
              // new sweep was added - set crystal_id and wavelength
              try {
                sweep.crystal_id = tab_w0.find_row(sweep_str).str(1);
              } catch(std::exception&) {
                sweep.crystal_id = "unknown";
              }
              try {
                const std::string& wave_id = tab_w1.find_row(sweep_str)[1];
                const std::string& wavelen = tab_w2.find_row(wave_id)[1];
                sweep.wavelength = (float) cif::as_number(wavelen, 0.);
              } catch(std::exception&) {}
            }
            sweep.frame_ids.insert(frame);
          }
        }

        // add datasets and set SweepInfo::dataset_id
        for (auto& sweep_pair : sweeps) {
          SweepInfo& si = sweep_pair.second;
          Mtz::Dataset* ds = mtz.dataset_with_name(si.crystal_id);
          if (ds == nullptr) {
            ds = &mtz.add_dataset(si.crystal_id);
            // both crystal name and dataset name are set to crystal_id
            ds->project_name = "unknown";
            ds->wavelength = si.wavelength;
          }
          si.dataset_id = ds->id;
        }

        // determine offset that makes frame numbers unique
        int cap = 0;
        for (auto& it : sweeps) {
          it.second.offset = cap;
          cap += *--it.second.frame_ids.end() + 1100;
          cap -= cap % 1000;
        }
        // add offset to BatchInfo::frame_id
        for (BatchInfo& p : batch_nums)
          if (p.sweep_id >= 0 && p.frame_id >= 0)
            p.frame_id += sweeps.at(p.sweep_id).offset;

        for (const auto& sweep_pair : sweeps) {
          const SweepInfo& sweep_info = sweep_pair.second;
          Mtz::Batch batch;
          batch.set_dataset_id(sweep_info.dataset_id);
          batch.set_cell(mtz.cell);
          batch.set_wavelength(sweep_info.wavelength);
          int min_frame = *sweep_info.frame_ids.begin();
          int max_frame = *--sweep_info.frame_ids.end();
          if (2 * sweep_info.frame_ids.size() > size_t(max_frame - min_frame)) {
            // probably consecutive range, even if some frames are missing
            for (int n = min_frame; n <= max_frame; ++n) {
              batch.number = n + sweep_info.offset;
              mtz.batches.push_back(batch);
            }
          } else {
            for (int n : sweep_info.frame_ids) {
              batch.number = n + sweep_info.offset;
              mtz.batches.push_back(batch);
            }
          }
        }
      }
    }

    // fill in the data
    mtz.data.resize(mtz.columns.size() * mtz.nreflections);
    size_t k = 0, row = 0;
    for (size_t i = 0; i < loop->values.size(); i += loop->tags.size()) {
      if (unmerged) {
        std::array<int, 3> hkl;
        for (int ii = 0; ii != 3; ++ii)
          hkl[ii] = cif::as_int(loop->values[i + indices[ii]]);
        int isym = hkl_mover->move_to_asu(hkl);
        for (int j = 0; j != 3; ++j)
          mtz.data[k++] = (float) hkl[j];
        mtz.data[k++] = (float) isym;
        mtz.data[k++] = batch_nums.empty() ? 1.f : (float) batch_nums[row++].frame_id;
      } else {
        for (int j = 0; j != 3; ++j)
          mtz.data[k++] = (float) cif::as_int(loop->values[i + indices[j]]);
      }
      size_t j = 3;
      if (uses_status)
        mtz.data[k++] = status_to_freeflag(loop->values[i + indices[j++]]);
      for (; j != indices.size(); ++j) {
        const std::string& v = loop->values[i + indices[j]];
        if (cif::is_null(v)) {
          mtz.data[k] = (float) NAN;
        } else {
          mtz.data[k] = (float) cif::as_number(v);
          if (std::isnan(mtz.data[k]))
            out << "Value #" << i + indices[j] << " in the loop is not a number: "
                << v << '\n';
        }
        ++k;
      }
    }
    return mtz;
  }

private:
  static float status_to_freeflag(const std::string& str) {
    char c = str[0];
    if (c == '\'' || c == '"')
      c = str[1];
    if (c == 'o')
      return 1.f;
    if (c == 'f')
      return 0.f;
    return NAN;
  }
};

} // namespace gemmi
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2015, LAAS-CNRS
// Authors: Thomas Moulard, Joseph Mirabel
//

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

#ifndef HPP_UTIL_TIMER_HH
#define HPP_UTIL_TIMER_HH

#include <chrono>
#include <hpp/util/config.hh>
#include <hpp/util/debug.hh>

namespace hpp {
namespace debug {
class HPP_UTIL_DLLAPI Timer {
 public:
  typedef std::chrono::high_resolution_clock clock_type;
  typedef clock_type::time_point time_point;
  typedef std::chrono::duration<double> duration_type;

  explicit Timer(bool autoStart = false);
  Timer(const Timer&);
  Timer& operator=(const Timer&);
  ~Timer();

  const time_point& start();
  const time_point& stop();
  double duration() const;

  const time_point& getStart() const;
  const time_point& getStop() const;

  std::ostream& print(std::ostream&) const;

 private:
  time_point start_;
  time_point end_;
};

#ifdef HPP_ENABLE_BENCHMARK

#define hppStartBenchmark(ID)           \
  hppDout(benchmark, #ID << ": start"); \
  ::hpp::debug::Timer _##ID##_timer_(true)

#define hppStopBenchmark(ID)             \
  do {                                   \
    _##ID##_timer_.stop();               \
    hppDout(benchmark, #ID << ": stop"); \
  } while (0)

#define hppDisplayBenchmark(ID) \
  hppDout(benchmark, #ID << ": " << _##ID##_timer_.duration());

#define hppBenchmark(data)                                                  \
  do {                                                                      \
    using namespace hpp;                                                    \
    using namespace ::hpp::debug;                                           \
    std::stringstream __ss;                                                 \
    __ss << data << iendl;                                                  \
    logging.benchmark.write(__FILE__, __LINE__, __PRETTY_FUNCTION__, __ss); \
  } while (0)

#else
#define hppStartBenchmark(ID)
#define hppStopBenchmark(ID)
#define hppDisplayBenchmark(ID)
#define hppBenchmark(data)
#endif  // HPP_ENABLE_BENCHMARK

/// \brief Computation of min, max and mean time from a set of measurements.
class HPP_UTIL_DLLAPI TimeCounter {
 public:
  struct Scope {
    Scope(TimeCounter& t) : tc(t) { t.start(); }
    ~Scope() { tc.stop(); }

    TimeCounter& tc;
  };

  typedef std::chrono::high_resolution_clock clock_type;
  typedef clock_type::time_point time_point;
  typedef std::chrono::duration<double> duration_type;

  TimeCounter(const std::string& name);

  void start();
  double stop();
  double last();
  void reset();

  double min() const;
  double max() const;
  double mean() const;
  double totalTime() const;

  std::ostream& print(std::ostream& os) const;

 private:
  std::string n_;
  unsigned long c_;
  duration_type t_, last_, min_, max_;
  time_point s_;
};

std::ostream& operator<<(std::ostream& os, const TimeCounter& tc);

#ifdef HPP_ENABLE_BENCHMARK

/// \addtogroup hpp_util_logging
/// \{

/// \brief Define a new TimeCounter
#define HPP_DEFINE_TIMECOUNTER(name) \
  ::hpp::debug::TimeCounter _##name##_timecounter_(#name)
/// \brief Compute the time spent in the current scope.
#define HPP_SCOPE_TIMECOUNTER(name)                             \
  ::hpp::debug::TimeCounter::Scope _##name##_scopetimecounter_( \
      _##name##_timecounter_)
/// \brief Start a watch.
#define HPP_START_TIMECOUNTER(name) _##name##_timecounter_.start()
/// \brief Stop a watch and save elapsed time.
#define HPP_STOP_TIMECOUNTER(name) _##name##_timecounter_.stop()
/// \brief Print last elapsed time to the logs.
#define HPP_DISPLAY_LAST_TIMECOUNTER(name)                                  \
  do {                                                                      \
    using namespace hpp;                                                    \
    using namespace ::hpp::debug;                                           \
    std::stringstream __ss;                                                 \
    __ss << #name << " last: " << _##name##_timecounter_.last() << iendl;   \
    logging.benchmark.write(__FILE__, __LINE__, __PRETTY_FUNCTION__, __ss); \
  } while (0)
/// \brief Print min, max and mean time of the time measurements.
#define HPP_DISPLAY_TIMECOUNTER(name)                                       \
  do {                                                                      \
    using namespace hpp;                                                    \
    using namespace ::hpp::debug;                                           \
    std::stringstream __ss;                                                 \
    __ss << _##name##_timecounter_ << iendl;                                \
    logging.benchmark.write(__FILE__, __LINE__, __PRETTY_FUNCTION__, __ss); \
  } while (0)
/// \brief Reset a TimeCounter.
#define HPP_RESET_TIMECOUNTER(name) _##name##_timecounter_.reset();
/// \brief Stream (\c operator<<) to the output stream.
#define HPP_STREAM_TIMECOUNTER(os, name) os << _##name##_timecounter_
/// \}
#else  // HPP_ENABLE_BENCHMARK
#define HPP_DEFINE_TIMECOUNTER(name) \
  struct _##name##_EndWithSemiColon_ {}
#define HPP_SCOPE_TIMECOUNTER(name)
#define HPP_START_TIMECOUNTER(name)
#define HPP_STOP_TIMECOUNTER(name)
#define HPP_DISPLAY_LAST_TIMECOUNTER(name)
#define HPP_DISPLAY_TIMECOUNTER(name)
#define HPP_RESET_TIMECOUNTER(name)
#define HPP_STREAM_TIMECOUNTER(os, name) os
#endif  // HPP_ENABLE_BENCHMARK

#define HPP_STOP_AND_DISPLAY_TIMECOUNTER(name) \
  HPP_STOP_TIMECOUNTER(name);                  \
  HPP_DISPLAY_TIMECOUNTER(name)

}  // end of namespace debug
}  // end of namespace hpp

#endif  // HPP_UTIL_TIMER_HH
<commit_msg>FIX: force system_clock<commit_after>// Copyright (c) 2015, LAAS-CNRS
// Authors: Thomas Moulard, Joseph Mirabel
//

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

#ifndef HPP_UTIL_TIMER_HH
#define HPP_UTIL_TIMER_HH

#include <chrono>
#include <hpp/util/config.hh>
#include <hpp/util/debug.hh>

namespace hpp {
namespace debug {
class HPP_UTIL_DLLAPI Timer {
 public:
  typedef std::chrono::system_clock clock_type;
  typedef clock_type::time_point time_point;
  typedef std::chrono::duration<double> duration_type;

  explicit Timer(bool autoStart = false);
  Timer(const Timer&);
  Timer& operator=(const Timer&);
  ~Timer();

  const time_point& start();
  const time_point& stop();
  double duration() const;

  const time_point& getStart() const;
  const time_point& getStop() const;

  std::ostream& print(std::ostream&) const;

 private:
  time_point start_;
  time_point end_;
};

#ifdef HPP_ENABLE_BENCHMARK

#define hppStartBenchmark(ID)           \
  hppDout(benchmark, #ID << ": start"); \
  ::hpp::debug::Timer _##ID##_timer_(true)

#define hppStopBenchmark(ID)             \
  do {                                   \
    _##ID##_timer_.stop();               \
    hppDout(benchmark, #ID << ": stop"); \
  } while (0)

#define hppDisplayBenchmark(ID) \
  hppDout(benchmark, #ID << ": " << _##ID##_timer_.duration());

#define hppBenchmark(data)                                                  \
  do {                                                                      \
    using namespace hpp;                                                    \
    using namespace ::hpp::debug;                                           \
    std::stringstream __ss;                                                 \
    __ss << data << iendl;                                                  \
    logging.benchmark.write(__FILE__, __LINE__, __PRETTY_FUNCTION__, __ss); \
  } while (0)

#else
#define hppStartBenchmark(ID)
#define hppStopBenchmark(ID)
#define hppDisplayBenchmark(ID)
#define hppBenchmark(data)
#endif  // HPP_ENABLE_BENCHMARK

/// \brief Computation of min, max and mean time from a set of measurements.
class HPP_UTIL_DLLAPI TimeCounter {
 public:
  struct Scope {
    Scope(TimeCounter& t) : tc(t) { t.start(); }
    ~Scope() { tc.stop(); }

    TimeCounter& tc;
  };

  typedef std::chrono::system_clock clock_type;
  typedef clock_type::time_point time_point;
  typedef std::chrono::duration<double> duration_type;

  TimeCounter(const std::string& name);

  void start();
  double stop();
  double last();
  void reset();

  double min() const;
  double max() const;
  double mean() const;
  double totalTime() const;

  std::ostream& print(std::ostream& os) const;

 private:
  std::string n_;
  unsigned long c_;
  duration_type t_, last_, min_, max_;
  time_point s_;
};

std::ostream& operator<<(std::ostream& os, const TimeCounter& tc);

#ifdef HPP_ENABLE_BENCHMARK

/// \addtogroup hpp_util_logging
/// \{

/// \brief Define a new TimeCounter
#define HPP_DEFINE_TIMECOUNTER(name) \
  ::hpp::debug::TimeCounter _##name##_timecounter_(#name)
/// \brief Compute the time spent in the current scope.
#define HPP_SCOPE_TIMECOUNTER(name)                             \
  ::hpp::debug::TimeCounter::Scope _##name##_scopetimecounter_( \
      _##name##_timecounter_)
/// \brief Start a watch.
#define HPP_START_TIMECOUNTER(name) _##name##_timecounter_.start()
/// \brief Stop a watch and save elapsed time.
#define HPP_STOP_TIMECOUNTER(name) _##name##_timecounter_.stop()
/// \brief Print last elapsed time to the logs.
#define HPP_DISPLAY_LAST_TIMECOUNTER(name)                                  \
  do {                                                                      \
    using namespace hpp;                                                    \
    using namespace ::hpp::debug;                                           \
    std::stringstream __ss;                                                 \
    __ss << #name << " last: " << _##name##_timecounter_.last() << iendl;   \
    logging.benchmark.write(__FILE__, __LINE__, __PRETTY_FUNCTION__, __ss); \
  } while (0)
/// \brief Print min, max and mean time of the time measurements.
#define HPP_DISPLAY_TIMECOUNTER(name)                                       \
  do {                                                                      \
    using namespace hpp;                                                    \
    using namespace ::hpp::debug;                                           \
    std::stringstream __ss;                                                 \
    __ss << _##name##_timecounter_ << iendl;                                \
    logging.benchmark.write(__FILE__, __LINE__, __PRETTY_FUNCTION__, __ss); \
  } while (0)
/// \brief Reset a TimeCounter.
#define HPP_RESET_TIMECOUNTER(name) _##name##_timecounter_.reset();
/// \brief Stream (\c operator<<) to the output stream.
#define HPP_STREAM_TIMECOUNTER(os, name) os << _##name##_timecounter_
/// \}
#else  // HPP_ENABLE_BENCHMARK
#define HPP_DEFINE_TIMECOUNTER(name) \
  struct _##name##_EndWithSemiColon_ {}
#define HPP_SCOPE_TIMECOUNTER(name)
#define HPP_START_TIMECOUNTER(name)
#define HPP_STOP_TIMECOUNTER(name)
#define HPP_DISPLAY_LAST_TIMECOUNTER(name)
#define HPP_DISPLAY_TIMECOUNTER(name)
#define HPP_RESET_TIMECOUNTER(name)
#define HPP_STREAM_TIMECOUNTER(os, name) os
#endif  // HPP_ENABLE_BENCHMARK

#define HPP_STOP_AND_DISPLAY_TIMECOUNTER(name) \
  HPP_STOP_TIMECOUNTER(name);                  \
  HPP_DISPLAY_TIMECOUNTER(name)

}  // end of namespace debug
}  // end of namespace hpp

#endif  // HPP_UTIL_TIMER_HH
<|endoftext|>


<commit_before>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_DEBUG_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_DEBUG_HPP

#include "detail/error.hpp"

namespace kgr {
namespace debug {

template<typename T, typename U, typename... Args>
auto service(U&& u, Args&&...) -> detail::enable_if_t<std::is_constructible<detail::ServiceError<T, Args...>, U>::value> {
	(void) detail::ServiceError<T, Args...> {std::forward<U>(u)};
}

template<typename T, typename U, typename... Args>
auto service(U&&, Args&&...) -> detail::enable_if_t<!std::is_constructible<detail::ServiceError<T, Args...>, U>::value> {
	static_assert(detail::false_t<T>::value, "No error detected.");
}

template<typename T>
auto service() -> detail::enable_if_t<std::is_default_constructible<detail::ServiceError<T>>::value> {
	(void) detail::ServiceError<T> {};
}

template<typename T>
auto service() -> detail::enable_if_t<!std::is_default_constructible<detail::ServiceError<T>>::value> {
	static_assert(detail::false_t<T>::value, "No error detected.");
}

}
}

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_DEBUG_HPP
<commit_msg>Clarified messages when there is no detected errors<commit_after>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_DEBUG_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_DEBUG_HPP

#include "detail/error.hpp"

namespace kgr {
namespace debug {

template<typename T, typename U, typename... Args>
auto service(U&& u, Args&&...) -> detail::enable_if_t<std::is_constructible<detail::ServiceError<T, Args...>, U>::value> {
	(void) detail::ServiceError<T, Args...> {std::forward<U>(u)};
}

template<typename T, typename U, typename... Args>
auto service(U&&, Args&&...) -> detail::enable_if_t<!std::is_constructible<detail::ServiceError<T, Args...>, U>::value> {
	static_assert(detail::false_t<T>::value, "No known error detected.");
}

template<typename T>
auto service() -> detail::enable_if_t<std::is_default_constructible<detail::ServiceError<T>>::value> {
	(void) detail::ServiceError<T> {};
}

template<typename T>
auto service() -> detail::enable_if_t<!std::is_default_constructible<detail::ServiceError<T>>::value> {
	static_assert(detail::false_t<T>::value, "No known error detected.");
}

}
}

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_DEBUG_HPP
<|endoftext|>