text:
//                 -- fcgi/client.hpp --
//
//            Copyright (c) Darren Garvey 2007.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
//
////////////////////////////////////////////////////////////////
#ifndef CGI_FCGI_CLIENT_HPP_INCLUDED__
#define CGI_FCGI_CLIENT_HPP_INCLUDED__

#include <vector>
///////////////////////////////////////////////////////////
#include <boost/shared_ptr.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/asio/buffer.hpp>
///////////////////////////////////////////////////////////
#include "boost/cgi/basic_client.hpp"
#include "boost/cgi/common/map.hpp"
#include "boost/cgi/fcgi/traits.hpp"
#include "boost/cgi/connections/shareable_tcp_socket.hpp"
#include "boost/cgi/detail/throw_error.hpp"
#include "boost/cgi/fcgi/specification.hpp"
#include "boost/cgi/fwd/basic_request_fwd.hpp"
#include "boost/cgi/error.hpp"
#include "boost/cgi/import/read.hpp"
#include "boost/cgi/import/buffer.hpp"
#include "boost/cgi/import/io_service.hpp"

#undef min
#undef max
#include <algorithm>

#if !defined(BOOST_CGI_NO_LOGGING) && !defined(NDEBUG)
#   include <iostream>
#endif

BOOST_CGI_NAMESPACE_BEGIN
 namespace common {

  /// A client that uses a TCP socket that owned by it.
  /// Construct
  template<>
  basic_client<
      ::BOOST_CGI_NAMESPACE::common::tags::fcgi
  >::basic_client()
    : request_id_(-1)
    , status_(none_)
    , total_sent_bytes_(0)
    , total_sent_packets_(0)
    , header_()
    , outbuf_()
    , keep_connection_(false)
  {
  }

  /// Override basic_client::close().
  /**
   * Closing a FastCGI means sending an END_REQUEST header
   * to the HTTP server and potentially closing the connection.
   *
   * Note that in general the HTTP server is responsible for the
   * lifetime of the connection, but can hand that control over
   * to the library (eg. if the server is set up to recycle
   * connections after N requests).
   */
  template<>
  boost::system::error_code
  basic_client<
      ::BOOST_CGI_NAMESPACE::common::tags::fcgi
  >::close(boost::uint64_t app_status, boost::system::error_code& ec)
  {
    // Note that the request may already be closed if the client aborts
    // the connection.
    if (!is_open())
      ec = error::already_closed;
    else
    {
      if ((constructed < status_) && (status_ < end_request_sent))
      {
        status_ = closed_;

        // Write an EndRequest packet to the server.
        outbuf_.clear();
        header_.reset(fcgi::spec_detail::END_REQUEST, request_id_, 8);

        fcgi::spec::end_request_body body(app_status, fcgi::spec_detail::REQUEST_COMPLETE);
        outbuf_.push_back(header_.data());
        outbuf_.push_back(body.data());
        write(*connection_, outbuf_, boost::asio::transfer_all(), ec);
      }
      status_ = closed_;

      if (!ec && !keep_connection_)
        connection_->close();
    }
    return ec;
  }

  /// Prepare a buffer by wrapping it into a FastCGI packet.
  /**
   * FastCGI dictates that data is sent in packets which identify
   * which request the data relates to, along with the size of
   * the packet.
   *
   * This function takes a buffer of data and creates another
   * buffer which includes the packet header information. As the
   * buffers themselves only contain pointers to the data the
   * overhead is negligible as the data is not copied.
   *
   * The lifetime of the header is guaranteed as it is kept in
   * the client object itself.
   */
  template<>
  template<typename ConstBufferSequence>
  void
  basic_client<
      ::BOOST_CGI_NAMESPACE::common::tags::fcgi
  >::prepare_buffer(const ConstBufferSequence& buf)
  {
    typename ConstBufferSequence::const_iterator iter = buf.begin();
    typename ConstBufferSequence::const_iterator end  = buf.end();

    outbuf_.clear();
    outbuf_.push_back(boost::asio::buffer(header_.data()));

    std::size_t total_buffer_size(0);
    for(; iter != end; ++iter)
    {
      boost::asio::const_buffer buffer(*iter);
      std::size_t new_buf_size( boost::asio::buffer_size(*iter) );
      if (total_buffer_size + new_buf_size
           > static_cast<std::size_t>(fcgi::spec::max_packet_size::value))
      {
        // If the send buffer is empty, extract a chunk of the
        // new buffer to send. If there is already some data
        // ready to send, don't add any more data to the pack.
        if (total_buffer_size == 0)
        {
          total_buffer_size
            = std::min<std::size_t>(new_buf_size,65500);
          /*
          std::cerr<< "Oversized buffer: " << total_buffer_size
                   << " / " << new_buf_size << " bytes sent\n";
          */
          outbuf_.push_back(
            boost::asio::buffer(*iter, total_buffer_size));
          break;
        }
        else
          break;
      }
      else
      {
        total_buffer_size += new_buf_size;
        outbuf_.push_back(*iter);
      }
    }
    header_.reset(fcgi::spec_detail::STDOUT, request_id_, total_buffer_size);
  }

  template<>
  void
  basic_client<
      ::BOOST_CGI_NAMESPACE::common::tags::fcgi
  >::handle_write(std::size_t bytes_transferred, boost::system::error_code& ec)
  {
    total_sent_bytes_ += bytes_transferred;
    total_sent_packets_ += 1;

    std::size_t total_buffer_size = static_cast<std::size_t>(header_.content_length());

#if !defined(BOOST_CGI_NO_LOGGING) && !defined(NDEBUG)
    std::ofstream log("../logs/fcgi_client.log", std::ios::out | std::ios::app);
    if (ec)
      std::cerr<< "Error " << ec << ": " << ec.message() << '\n';
    else
      //std::cerr
      log
        << "Transferred " << total_buffer_size
        << " (+" << (bytes_transferred - total_buffer_size)
        << " protocol) bytes (running total: "
        << total_sent_bytes_ << " bytes; "
        << total_sent_packets_ << " packets).\n";
#endif // !defined(BOOST_CGI_NO_LOGGING) && !defined(NDEBUG)

    // Now remove the protocol overhead for the caller, who
    // doesn't want to count it.
    bytes_transferred -= fcgi::spec::header_length::value;
    // Check everything was written ok.
    if (!ec && bytes_transferred != total_buffer_size)
      ec = ::BOOST_CGI_NAMESPACE::fcgi::error::couldnt_write_complete_packet;
  }

  /// Write some data to the client.
  /**
   * Currently this actually writes an entire packet - which may be up
   * to 65,535 bytes in size - as the connection may potentially be
   * multiplexed and shared between requests.
   */
  template<>
  template<typename ConstBufferSequence>
  std::size_t
  basic_client<
      ::BOOST_CGI_NAMESPACE::common::tags::fcgi
  >::write_some(
      const ConstBufferSequence& buf
    , boost::system::error_code& ec
  )
  {
    prepare_buffer(buf);

    std::size_t bytes_transferred
      = boost::asio::write(*connection_, outbuf_
                          , boost::asio::transfer_all(), ec);

    handle_write(bytes_transferred, ec);

    return bytes_transferred;
  }

  /// Write some data to the client.
  /**
   * Currently this actually writes an entire packet - which may be up
   * to 65,535 bytes in size - as the connection may potentially be
   * multiplexed and shared between requests.
   */
  template<>
  template<typename ConstBufferSequence, typename Handler>
  void
  basic_client<
    ::BOOST_CGI_NAMESPACE::common::tags::fcgi
  >::async_write_some(
      const ConstBufferSequence& buf
    , Handler handler
  )
  {
    prepare_buffer(buf);
    boost::system::error_code ec;
    std::size_t bytes_transferred
      = boost::asio::write(*connection_, outbuf_
                          , boost::asio::transfer_all(), ec);
    handle_write(bytes_transferred, ec);
    handler(bytes_transferred, ec);
  }

 } // namespace common

namespace fcgi {
    typedef
      common::basic_client<
        ::BOOST_CGI_NAMESPACE::common::tags::fcgi
      >
    client;
} // namespace fcgi

BOOST_CGI_NAMESPACE_END

#endif // CGI_FCGI_CLIENT_HPP_INCLUDED__


text: #include <boost/metaparse/v1/foldr_start_with_parser.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/**
 * @file
 * Declares a Unicode string utility type.
 */
#pragma once

#include <boost/iterator/iterator_facade.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/optional.hpp>
#include <unicode/utext.h>
#include <unicode/ubrk.h>
#include <string>
#include <exception>
#include <limits>

namespace puppet { namespace unicode {

    // Forward declaration of string
    struct string;

    /**
     * Exception for unicode errors.
     */
    struct unicode_exception : std::runtime_error
    {
        using std::runtime_error::runtime_error;
    };

    /**
     * An iterator type for iterating over graphemes in a UTF-8 encoded string.
     * This iterator outputs an iterator range of two character pointers in the original string's range.
     * The range represents the UTF-8 code units that makes up a single Unicode grapheme.
     */
    struct string_iterator :
        boost::iterator_facade<
            string_iterator,
            typename boost::iterator_range<char const*> const,
            boost::forward_traversal_tag
        >
    {
        /**
         * Constructs an empty iterator.
         * An empty iterator is semantically at the "end".
         */
        string_iterator() = default;

        /**
         * Constructs an iterator for the given UTF-8 encoded string.
         * @param string The string being iterated.
         * @param iterate_units Iterates the code units of the UTF-8 data instead of graphemes.
         * @param reversed True to iterate in reverse or false to iterate in a forward fashion.
         */
        explicit string_iterator(std::string const& string, bool iterate_units = false, bool reversed = false);

        /**
         * Constructs an iterator for the given UTF-8 encoded string data.
         * @param data The UTF-8 string data being iterated.
         * @param length The length of the data, in code units (i.e. bytes).
         * @param iterate_units Iterates the code units of the UTF-8 data instead of graphemes.
         * @param reversed True to iterate in reverse or false to iterate in a forward fashion.
         */
        string_iterator(char const* data, size_t length, bool iterate_units = false, bool reversed = false);

        /**
         * Copy constructor for string iterator.
         * @param other The other string iterator to copy.
         */
        string_iterator(string_iterator const& other);

        /**
         * Move constructor for string iterator.
         * @param other The other string iterator to move.
         */
        string_iterator(string_iterator&& other) noexcept;

        /**
         * Copy assignment operator for string iterator.
         * @param other The other string iterator to copy.
         * @return Returns this string iterator.
         */
        string_iterator& operator=(string_iterator const& other);

        /**
         * Move assignment operator for string iterator.
         * @param other The other string iterator to move.
         * @return Returns this string iterator.
         */
        string_iterator& operator=(string_iterator&& other) noexcept;

        /**
         * Destructor for string iterator.
         */
        ~string_iterator();

     private:
        friend class boost::iterator_core_access;

        void increment();
        bool equal(string_iterator const& other) const;
        reference dereference() const;
        void close(bool release = true);

        char const* _data = nullptr;
        size_t _length = 0;
        UText _text = UTEXT_INITIALIZER;
        UBreakIterator* _iterator = nullptr;
        boost::iterator_range<char const*> _value;
        bool _iterate_units = false;
        bool _reversed = false;
    };

    /**
     * An iterator type for splitting a UTF-8 encoded string by Unicode graphemes.
     * This iterator outputs an iterator range of two character pointers in the original string's range.
     * The range represents the split part.  An empty range indicates sequential delimiters.
     */
    struct split_iterator :
        boost::iterator_facade<
            split_iterator,
            typename boost::iterator_range<char const*> const,
            boost::forward_traversal_tag
        >
    {
        /**
         * Constructs an empty iterator.
         * An empty iterator is semantically at the "end".
         */
        split_iterator() = default;

        /**
         * Constructs a split iterator.
         * @param string The string being split.
         * @param delimiter The delimiter string.
         * @param delimiter_length The length of the delimiter, in code units.
         * @param ignore_case True to ignore case differences or false to respect case differences in the search.
         */
        split_iterator(unicode::string const& string, char const* delimiter, size_t delimiter_length, bool ignore_case = false);

     private:
        friend class boost::iterator_core_access;

        void increment();
        bool equal(split_iterator const& other) const;
        reference dereference() const;
        void close();

        string const* _string = nullptr;
        char const* _delimiter = nullptr;
        size_t _delimiter_length = 0;
        char const* _start = nullptr;
        boost::iterator_range<char const*> _value;
        bool _ignore_case = false;
    };

    /**
     * A utility type to handle UTF-8 encoded strings.
     * This type can be used to properly handle unnormalized Unicode graphemes.
     * The string data used by this utility type is stored externally (i.e this
     * type does not store an internal copy of the string data).
     */
    struct string
    {
        /**
         * Represents the const iterator for the string type.
         */
        using const_iterator = unicode::string_iterator;

        /**
         * Represents the const reverse iterator for the string type.
         */
        using const_reverse_iterator = unicode::string_iterator;

        /**
         * Represents the value type (segments representing Unicode graphemes)
         */
        using value_type = unicode::string_iterator::value_type;

        /**
         * Represents the greatest possible position in the string.
         */
        static const size_t npos;

        /**
         * Constructs a Unicode string from a UTF-8 encoded std::string.
         * @param data The string containing the UTF-8 encoded data.
         */
        explicit string(std::string const& data);

        /**
         * Constructs a Unicode string from a UTF-8 encoded null terminated C-string.
         * @param data THe string containing the UTF-8 encoded data.
         */
        explicit string(char const* data);

        /**
         * Gets an iterator to the beginning.
         * @return Returns an iterator to the beginning.
         */
        const_iterator begin() const;

        /**
         * Gets an iterator to the end.
         * @return Returns an iterator to the end.
         */
        const_iterator end() const;

        /**
         * Gets a const iterator to the beginning.
         * @return Returns a const iterator to the beginning.
         */
        const_iterator cbegin() const;

        /**
         * Gets a const iterator to the end.
         * @return Returns a const iterator to the end.
         */
        const_iterator cend() const;

        /**
         * Gets a reverse iterator to the beginning.
         * @return Returns a reverse iterator to the beginning.
         */
        const_reverse_iterator rbegin() const;

        /**
         * Gets a reverse iterator to the end.
         * @return Returns a reverse iterator to the end.
         */
        const_reverse_iterator rend() const;

        /**
         * Gets a const reverse iterator to the beginning.
         * @return Returns a const reverse iterator to the beginning.
         */
        const_reverse_iterator crbegin() const;

        /**
         * Gets a const reverse iterator to the end.
         * @return Returns a const reverse iterator to the end.
         */
        const_reverse_iterator crend() const;

        /**
         * Gets the number of graphemes in the string.
         * @return Returns the number of graphemes in the string.
         */
        size_t graphemes() const noexcept;

        /**
         * Gets the number of code units (i.e. bytes) in the string.
         * @return Returns the size of the string in code units.
         */
        size_t units() const noexcept;

        /**
         * Determines if the string is empty.
         * @return Returns true if the string is empty or false if not.
         */
        bool empty() const noexcept;

        /**
         * Determines if the string is invariant (i.e. contains only ASCII characters).
         * @return Returns true if the string is invariant or false if not.
         */
        bool invariant() const noexcept;

        /**
         * Gets the pointer to the start of the string's UTF-8 data.
         * @return Returns a pointer to the start of the string's UTF-8 data.
         */
        char const* data() const noexcept;

        /**
         * Gets a substring of the original string.
         * Note: unlike std::string, this is an O(N) operation in terms of locating the substring's range.
         * @param start The starting grapheme position.
         * @param length The length of the substring, in graphemes.
         * @return Returns the requested substring.
         */
        std::string substr(size_t start = 0, size_t length = npos) const;

        /**
         * Compares this string to the given Unicode string.
         * @param other The other string to compare.
         * @param ignore_case True to ignore case differences or false to respect case differences in the comparison.
         * @return Returns <0 if the given string is "less than" this string, 0 if they are equal, or >0 if the given string is "greater than".
         */
        int compare(string const& other, bool ignore_case = false) const;

        /**
         * Compares this string to the given UTF-8 encoded std::string.
         * @param other The other string to compare.
         * @param ignore_case True to ignore case differences or false to respect case differences in the comparison.
         * @return Returns <0 if the given string is "less than" this string, 0 if they are equal, or >0 if the given string is "greater than".
         */
        int compare(std::string const& other, bool ignore_case = false) const;

        /**
         * Compares this string to the given UTF-8 encoded C-string.
         * @param other The other string to compare.
         * @param ignore_case True to ignore case differences or false to respect case differences in the comparison.
         * @return Returns <0 if the given string is "less than" this string, 0 if they are equal, or >0 if the given string is "greater than".
         */
        int compare(char const* other, bool ignore_case = false) const;

        /**
         * Determines if this string starts with the other string.
         * @param other The other string.
         * @return Returns true if this string starts with the other string or false if not.
         */
        bool starts_with(unicode::string const& other) const;

        /**
         * Determines if this string starts with the other string.
         * @param other The other string.
         * @return Returns true if this string starts with the other string or false if not.
         */
        bool starts_with(std::string const& other) const;

        /**
         * Determines if this string starts with the other string.
         * @param other The other string.
         * @return Returns true if this string starts with the other string or false if not.
         */
        bool starts_with(char const* other) const;

        /**
         * Converts the string to lowercase.
         * @return Returns the lowercased string.
         */
        std::string lowercase() const;

        /**
         * Converts the string to uppercase.
         * @return Returns the uppercased string.
         */
        std::string uppercase() const;

        /**
         * Capitalizes the first grapheme of the string only.
         * Note: this is like Unicode title casing, but this is limited to only the first word.
         * @return Returns the capitalized string.
         */
        std::string capitalize() const;

        /**
         * Capitalizes the first grapheme following '::' segments.
         * This is typically used for Puppet type names.
         * @return Returns the segment capitalized string.
         */
        std::string capitalize_segments() const;

        /**
         * Trims whitespace from the left (start) of the string.
         * @return Returns the trimmed string.
         */
        std::string trim_left() const;

        /**
         * Trims whitespace from the right (end) of the string.
         * @return Returns the trimmed string.
         */
        std::string trim_right() const;

        /**
         * Trims whitespace from both sides (start and end) of the string.
         * @return Returns the trimmed string.
         */
        std::string trim() const;

        /**
         * Determines if any of the given graphemes are contained in this string.
         * @param graphemes The string containing the graphemes to check.
         * @return Returns true if any of the graphemes are contained in the string or false if none of the graphemes are contained.
         */
        bool contains_any(string const& graphemes) const;

        /**
         * Determines if any of the given graphemes are contained in this string.
         * @param graphemes The UTF-8 encoded string containing the graphemes to check.
         * @return Returns true if any of the graphemes are contained in the string or false if none of the graphemes are contained.
         */
        bool contains_any(std::string const& graphemes) const;

        /**
         * Determines if any of the given graphemes are contained in this string.
         * @param graphemes The UTF-8 encoded string containing the graphemes to check.
         * @return Returns true if any of the graphemes are contained in the string or false if none of the graphemes are contained.
         */
        bool contains_any(char const* graphemes) const;

        /**
         * Finds the range of the given substring.
         * @param substring The substring to find.
         * @param ignore_case True to ignore case differences or false to respect case differences in the search.
         * @return Returns the range of the graphemes matching the given substring or an empty range if not found.
         */
        value_type find(string const& substring, bool ignore_case = false) const;

        /**
         * Finds the first code unit position (i.e. byte offset) of the given substring.
         * @param substring The substring to find.
         * @param ignore_case True to ignore case differences or false to respect case differences in the search.
         * @return Returns the range of the graphemes matching the given substring or an empty range if not found.
         */
        value_type find(std::string const& substring, bool ignore_case = false) const;

        /**
         * Finds the first code unit position (i.e. byte offset) of the given substring.
         * @param substring The substring to find.
         * @param ignore_case True to ignore case differences or false to respect case differences in the search.
         * @return Returns the range of the graphemes matching the given substring or an empty range if not found.
         */
        value_type find(char const* substring, bool ignore_case = false) const;

        /**
         * Gets a beginning split iterator based on the given delimiter.
         * @param delimiter The delimiter to split the string with.
         * @param ignore_case True to ignore case differences or false to respect case differences in the search.
         * @return Returns a beginning split iterator.
         */
        split_iterator split_begin(string const& delimiter, bool ignore_case = false);

        /**
         * Gets a beginning split iterator based on the given delimiter.
         * @param delimiter The delimiter to split the string with.
         * @param ignore_case True to ignore case differences or false to respect case differences in the search.
         * @return Returns a beginning split iterator.
         */
        split_iterator split_begin(std::string const& delimiter, bool ignore_case = false);

        /**
         * Gets a beginning split iterator based on the given delimiter.
         * @param delimiter The delimiter to split the string with.
         * @param ignore_case True to ignore case differences or false to respect case differences in the search.
         * @return Returns a beginning split iterator.
         */
        split_iterator split_begin(char const* delimiter, bool ignore_case = false);

        /**
         * Gets an ending split iterator.
         * @return Returns an ending split iterator.
         */
        split_iterator split_end() const;

        /**
         * Gets the "end of string" pointer (exclusive).
         * @return Returns the end of string pointer.
         */
        char const* eos() const noexcept;

        /**
         * Appends a codepoint in UTF-8 to the given string.
         * @param codepoint The codepoint to append.
         * @param string The string to append the UTF-8 code units to.
         * @return Returns true if the codepoint was valid or false if not.
         */
        static bool append_utf8(char32_t codepoint, std::string& string);

     private:
        friend struct split_iterator;
        bool starts_with(char const* data, size_t length) const;
        std::string trim(bool left, bool right) const;
        bool contains_any(char const* data, size_t length) const;
        value_type find(char const* start, char const* data, size_t length, bool ignore_case) const;
        void count_graphemes();

        char const* _data;
        size_t _graphemes;
        size_t _units;
    };

    /**
     * Equality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are equal or false if not.
     */
    bool operator==(string const& left, string const& right);

    /**
     * Equality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are equal or false if not.
     */
    bool operator==(string const& left, std::string const& right);

    /**
     * Equality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are equal or false if not.
     */
    bool operator==(string const& left, char const* right);

    /**
     * Equality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are equal or false if not.
     */
    bool operator==(std::string const& left, string const& right);

    /**
     * Equality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are equal or false if not.
     */
    bool operator==(char const* left, string const& right);

    /**
     * Inequality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are not equal or false if they are equal.
     */
    bool operator!=(string const& left, string const& right);

    /**
     * Inequality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are not equal or false if they are equal.
     */
    bool operator!=(string const& left, std::string const& right);

    /**
     * Inequality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are not equal or false if they are equal.
     */
    bool operator!=(string const& left, char const* right);

    /**
     * Inequality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are not equal or false if they are equal.
     */
    bool operator!=(std::string const& left, string const& right);

    /**
     * Inequality operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the two strings are not equal or false if they are equal.
     */
    bool operator!=(char const* left, string const& right);

    /**
     * Less than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than the right or false if not.
     */
    bool operator<(string const& left, string const& right);

    /**
     * Less than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than the right or false if not.
     */
    bool operator<(string const& left, std::string const& right);

    /**
     * Less than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than the right or false if not.
     */
    bool operator<(string const& left, char const* right);

    /**
     * Less than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than the right or false if not.
     */
    bool operator<(std::string const& left, string const& right);

    /**
     * Less than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than the right or false if not.
     */
    bool operator<(char const* left, string const& right);

    /**
     * Less than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than or equal to the right or false if not.
     */
    bool operator<=(string const& left, string const& right);

    /**
     * Less than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than or equal to the right or false if not.
     */
    bool operator<=(string const& left, std::string const& right);

    /**
     * Less than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than or equal to the right or false if not.
     */
    bool operator<=(string const& left, char const* right);

    /**
     * Less than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than or equal to the right or false if not.
     */
    bool operator<=(std::string const& left, string const& right);

    /**
     * Less than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is less than or equal to the right or false if not.
     */
    bool operator<=(char const* left, string const& right);

    /**
     * Greater than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than the right or false if not.
     */
    bool operator>(string const& left, string const& right);

    /**
     * Greater than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than the right or false if not.
     */
    bool operator>(string const& left, std::string const& right);

    /**
     * Greater than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than the right or false if not.
     */
    bool operator>(string const& left, char const* right);

    /**
     * Greater than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than the right or false if not.
     */
    bool operator>(std::string const& left, string const& right);

    /**
     * Greater than operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than the right or false if not.
     */
    bool operator>(char const* left, string const& right);

    /**
     * Greater than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than or equal to the right or false if not.
     */
    bool operator>=(string const& left, string const& right);

    /**
     * Greater than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than or equal to the right or false if not.
     */
    bool operator>=(string const& left, std::string const& right);

    /**
     * Greater than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than or equal to the right or false if not.
     */
    bool operator>=(string const& left, char const* right);

    /**
     * Greater than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than or equal to the right or false if not.
     */
    bool operator>=(std::string const& left, string const& right);

    /**
     * Greater than or equal to operator for string.
     * @param left The left string to compare.
     * @param right The right string to compare.
     * @return Returns true if the left is greater than or equal to the right or false if not.
     */
    bool operator>=(char const* left, string const& right);

    /**
     * Stream insertion operator for string.
     * @param os The output stream to write the runtime string to.
     * @param string The runtime string to write.
     * @return Returns the given output stream.
     */
    std::ostream& operator<<(std::ostream& os, unicode::string const& string);

    /**
     * Hashes the string value.
     * @param string The string value to hash.
     * @return Returns the hash value for the value.
     */
    size_t hash_value(unicode::string const& string);

}}  // namespace puppet::unicode

max_stars_repo_name: puppetlabs/puppetcpp

max_issues_repo_name: puppetlabs/puppetcpp

max_forks_repo_name: puppetlabs/puppetcpp


text:
// smooth: Lie Theory for Robotics
// https://github.com/pettni/smooth
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
//
// Copyright (c) 2021 Petter Nilsson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#ifndef SMOOTH__IMPL__SO2_HPP_
#define SMOOTH__IMPL__SO2_HPP_

#include <Eigen/Core>

#include "common.hpp"

namespace smooth {

/**
 * @brief SO(2) Lie Group represented as C^1
 *
 * Memory layout
 * -------------
 * Group:    qz qw
 * Tangent:  Ωz
 *
 * Lie group Matrix form
 * ---------------------
 * [ qw -qz ]
 * [ qz  qw ]
 *
 * Lie algebra Matrix form
 * -----------------------
 * [ 0 -Ωz ]
 * [ Ωz  0 ]
 *
 * Constraints
 * -----------
 * Group:   qz * qz + qw * qw = 1
 * Tangent: -pi < Ωz <= pi
 */
template<typename _Scalar>
class SO2Impl
{
public:
  using Scalar = _Scalar;

  static constexpr Eigen::Index RepSize = 2;
  static constexpr Eigen::Index Dim     = 2;
  static constexpr Eigen::Index Dof     = 1;

  SMOOTH_DEFINE_REFS;

  static void setIdentity(GRefOut g_out) { g_out << Scalar(0), Scalar(1); }

  static void setRandom(GRefOut g_out)
  {
    using std::sin, std::cos;
    const Scalar u = Eigen::internal::template random_impl<Scalar>::run(0, 2 * M_PI);
    g_out << sin(u), cos(u);
  }

  static void matrix(GRefIn g_in, MRefOut m_out) { m_out << g_in(1), -g_in(0), g_in(0), g_in(1); }

  static void composition(GRefIn g_in1, GRefIn g_in2, GRefOut g_out)
  {
    g_out << g_in1[0] * g_in2[1] + g_in1[1] * g_in2[0], g_in1[1] * g_in2[1] - g_in1[0] * g_in2[0];
  }

  static void inverse(GRefIn g_in, GRefOut g_out) { g_out << -g_in[0], g_in[1]; }

  static void log(GRefIn g_in, TRefOut a_out)
  {
    using std::atan2;
    a_out << atan2(g_in[0], g_in[1]);
  }

  static void Ad(GRefIn, TMapRefOut A_out) { A_out.setIdentity(); }

  static void exp(TRefIn a_in, GRefOut g_out)
  {
    using std::cos, std::sin;
    g_out << sin(a_in.x()), cos(a_in.x());
  }

  static void hat(TRefIn a_in, MRefOut A_out) { A_out << Scalar(0), -a_in(0), a_in(0), Scalar(0); }

  static void vee(MRefIn A_in, TRefOut a_out) { a_out << (A_in(1, 0) - A_in(0, 1)) / Scalar(2); }

  static void ad(TRefIn, TMapRefOut A_out) { A_out.setZero(); }

  static void dr_exp(TRefIn, TMapRefOut A_out) { A_out.setIdentity(); }

  static void dr_expinv(TRefIn, TMapRefOut A_out) { A_out.setIdentity(); }
};

}  // namespace smooth

#endif  // SMOOTH__IMPL__SO2_HPP_

max_stars_repo_name: NamDinhRobotics/smooth

max_issues_repo_name: NamDinhRobotics/smooth

max_forks_repo_name: NamDinhRobotics/smooth


text:
//Copyright (c) 2014 Singapore-MIT Alliance for Research and Technology
//Licensed under the terms of the MIT License, as described in the file:
//license.txt   (http://opensource.org/licenses/MIT)

/*
 * Individual.cpp
 *
 *  Created on: 3 Sep, 2014
 *  Author: Chetan Rogbeer <chetan.rogbeer@smart.mit.edu>
 */

#include <database/entity/Individual.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

using namespace sim_mob::long_term;

Individual::Individual( BigSerial id, BigSerial individualTypeId, BigSerial householdId, BigSerial jobId, BigSerial ethnicityId, BigSerial employmentStatusId,
                        BigSerial genderId, BigSerial educationId, BigSerial occupationId, BigSerial vehicleCategoryId, BigSerial transitCategoryId,
                        BigSerial ageCategoryId, BigSerial residentialStatusId, bool householdHead, float income, int memberId, bool workAtHome, bool carLicense,
                        bool motorLicense, bool vanbusLicense, std::tm dateOfBirth, BigSerial studentId, BigSerial industryId, BigSerial ageDetailedCategory, int taxiDriver, int fixed_workplace, int fixed_hours) :
                        id(id), individualTypeId(individualTypeId), householdId(householdId), jobId(jobId), ethnicityId(ethnicityId), employmentStatusId(employmentStatusId),
                        genderId(genderId), educationId(educationId), occupationId(occupationId), vehicleCategoryId(vehicleCategoryId), transitCategoryId(transitCategoryId),
                        ageCategoryId(ageCategoryId), residentialStatusId(residentialStatusId), householdHead(householdHead), income(income), memberId(memberId), workAtHome(workAtHome),
                        carLicense(carLicense), motorLicense(motorLicense), vanbusLicense(vanbusLicense), dateOfBirth(dateOfBirth),
                         studentId(studentId), industryId(industryId), ageDetailedCategory(ageDetailedCategory), taxiDriver(taxiDriver), fixed_workplace(fixed_workplace), fixed_hours(fixed_hours){}

Individual::~Individual() {}

Individual& Individual::operator=(const Individual& source)
{
    this->id = source.id;
    this->individualTypeId = source.individualTypeId;
    this->householdId = source.householdId;
    this->jobId = source.jobId;
    this->ethnicityId = source.ethnicityId;
    this->employmentStatusId = source.employmentStatusId;
    this->genderId = source.genderId;
    this->educationId = source.educationId;
    this->occupationId = source.occupationId;
    this->vehicleCategoryId = source.vehicleCategoryId;
    this->transitCategoryId = source.transitCategoryId;
    this->ageCategoryId = source.ageCategoryId;
    this->residentialStatusId = source.residentialStatusId;
    this->householdHead = source.householdHead;
    this->income = source.income;
    this->memberId = source.memberId;
    this->workAtHome = source.workAtHome;
    this->carLicense = source.carLicense;
    this->motorLicense = source.motorLicense;
    this->vanbusLicense = source.vanbusLicense;
    this->dateOfBirth = source.dateOfBirth;
    this->studentId = source.studentId;
    this->industryId = source.industryId;
    this->ageDetailedCategory = source.ageDetailedCategory;
    this->taxiDriver = source.taxiDriver;
    this->fixed_workplace = source.fixed_workplace;
    this->fixed_hours = source.fixed_hours;

    return *this;
}

template<class Archive>
void Individual::serialize(Archive & ar,const unsigned int version)
{
    ar & id;
    ar & individualTypeId;
    ar & householdId;
    ar & jobId;
    ar & ethnicityId;
    ar & employmentStatusId;
    ar & genderId;
    ar & educationId;
    ar & occupationId;
    ar & vehicleCategoryId;
    ar & transitCategoryId;
    ar & ageCategoryId;
    ar & residentialStatusId;
    ar & householdHead;
    ar & income;
    ar & memberId;
    ar & workAtHome;
    ar & carLicense;
    ar & motorLicense;
    ar & vanbusLicense;
    ar & BOOST_SERIALIZATION_NVP(dateOfBirth.tm_year);
    ar & BOOST_SERIALIZATION_NVP(dateOfBirth.tm_mon);
    ar & BOOST_SERIALIZATION_NVP(dateOfBirth.tm_mday);
    dateOfBirth.tm_year = dateOfBirth.tm_year+1900;
    ar & studentId;
    ar & industryId;
    ar & ageDetailedCategory;
    ar & taxiDriver;
    ar & fixed_workplace;
    ar & fixed_hours;

}

void Individual::saveData(std::vector<Individual*> &individuals)
{
    // make an archive
    std::ofstream ofs(filename);
    boost::archive::binary_oarchive oa(ofs);
    oa & individuals;
}

std::vector<Individual*> Individual::loadSerializedData()
{
    std::vector<Individual*> individuals;
    // Restore from saved data and print to verify contents
    std::vector<Individual*> restored_info;
    {
        // Create and input archive
        std::ifstream ifs( filename );
        boost::archive::binary_iarchive ar( ifs );

        // Load the data
        ar & restored_info;
    }

    for (auto *itr :restored_info)
    {
        Individual *ind = itr;
        individuals.push_back(ind);
    }

    return individuals;

}

BigSerial Individual::getId() const
{
    return id;
}

BigSerial Individual::getIndividualTypeId() const
{
    return individualTypeId;
}

BigSerial Individual::getHouseholdId() const
{
    return householdId;
}

BigSerial Individual::getJobId() const
{
    return jobId;
}

BigSerial Individual::getEthnicityId() const
{
    return ethnicityId;
}

BigSerial Individual::getEmploymentStatusId() const
{
    return employmentStatusId;
}

BigSerial Individual::getGenderId() const
{
    return genderId;
}

BigSerial Individual::getEducationId() const
{
    return educationId;
}

BigSerial Individual::getOccupationId() const
{
    return occupationId;
}

BigSerial Individual::getVehicleCategoryId() const
{
    return vehicleCategoryId;
}

BigSerial Individual::getTransitCategoryId() const
{
    return transitCategoryId;
}

BigSerial Individual::getAgeCategoryId() const
{
    return ageCategoryId;
}

BigSerial Individual::getResidentialStatusId() const
{
    return residentialStatusId;
}

bool Individual::getHouseholdHead() const
{
    return householdHead;
}

float Individual::getIncome() const
{
    return income;
}

int Individual::getMemberId() const
{
    return memberId;
}

bool Individual::getWorkAtHome() const
{
    return workAtHome;
}

bool Individual::getCarLicense() const
{
    return carLicense;
}

bool Individual::getMotorLicense() const
{
    return motorLicense;
}

bool Individual::getVanBusLicense() const
{
    return vanbusLicense;
}

std::tm Individual::getDateOfBirth() const
{
    return dateOfBirth;
}

bool Individual::getIsPrimarySchoolWithin5Km(BigSerial primarySchoolId) const
{
    boost::unordered_map<BigSerial,School*>::const_iterator itr = primarySchoolsWithin5KmById.find(primarySchoolId);
    if (itr != primarySchoolsWithin5KmById.end())
    {
        return true;
    }
    return false;
}

BigSerial Individual::getStudentId() const
{
    return studentId;
}

BigSerial Individual::getIndustryId() const
{
    return industryId;
}

BigSerial Individual::getAgeDetailedCategory() const
{
    return ageDetailedCategory;
}

int       Individual::getTaxiDriver() const
{
    return taxiDriver;
}

int       Individual::getFixed_workplace() const
{
    return fixed_workplace;
}

int       Individual::getFixed_hours() const
{
    return fixed_hours;
}

void Individual::setDateOfBirth( std::tm dob )
{
    this->dateOfBirth = dob;
}

void Individual::addprimarySchoolIdWithin5km(BigSerial schoolId,School *primarySchool)
{
    this->primarySchoolsWithin5KmById.insert(std::make_pair(schoolId,primarySchool));
}

namespace sim_mob
{
    namespace long_term
    {
        std::ostream& operator<<(std::ostream& strm, const Individual& data)
        {
            return strm << "{" << "\"id \":\"" << data.id << "\","
                        << "\"individualTypeId \":\""   << data.individualTypeId << "\","
                        << "\"householdId \":\""        << data.householdId << "\","
                        << "\"jobId \":\""              << data.jobId << "\","
                        << "\"ethnicityId \":\""        << data.ethnicityId << "\","
                        << "\"employmentStatusId \":\"" << data.employmentStatusId
                        << "\"," << "\"genderId \":\""  << data.genderId << "\","
                        << "\"educationId \":\""        << data.educationId << "\","
                        << "\"occupationId \":\""       << data.occupationId << "\","
                        << "\"vehiculeCategoryId \":\"" << data.vehicleCategoryId << "\","
                        << "\"transitCategoryId \":\""  << data.transitCategoryId << "\","
                        << "\"ageCategoryId \":\""      << data.ageCategoryId << "\","
                        << "\"residentialStatusId \":\"" << data.residentialStatusId << "\","
                        << "\"householdHead \":\""      << data.householdHead << "\","
                        << "\"income \":\""     << data.income << "\","
                        << "\"memberId \":\""   << data.memberId << "\","
                        << "\"workerAtHome \":\""   << data.workAtHome << "\","
                        << "\"carLicense \":\"" << data.carLicense << "\","
                        << "\"motorLicense \":\"" << data.motorLicense << "\","
                        << "\"vanbusLicense \":\"" << data.vanbusLicense << "\","
                        << "\"dateOfBirth \":\""    << data.dateOfBirth.tm_year << " " << data.dateOfBirth.tm_mon   << " " << data.dateOfBirth.tm_mday << "\"" << "}";
        }
    }
}

ext: cpp


text:
#pragma once

#include <lib/utility.hpp>

#include <boost/functional/value_factory.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/container.hpp>
#include <boost/fusion/functional.hpp>
#include <boost/fusion/support.hpp>
#include <boost/fusion/tuple.hpp>
#include <boost/fusion/view.hpp>
#include <boost/mp11.hpp>
#include <boost/mpl/bool.hpp>

#include <cstddef>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>

namespace xzr
{
namespace tuple
{
namespace impl
{
template <class Container>
struct emplace_back_t
{
    template <class... Args>
    void operator()(Args&&... args)
    {
        container.emplace_back(std::forward<Args>(args)...);
    }
    Container& container{};
};
} // namespace impl
template <class Container, class... Args>
inline void emplace_back_from_tuple(Container& out, std::tuple<Args...>&& args)
{
    boost::mp11::tuple_apply(impl::emplace_back_t<Container>{out}, std::forward<std::tuple<Args...>>(args));
}

template <class Container, class FusionSeq, class FS = typename std::remove_reference<FusionSeq>::type>
inline typename std::enable_if<boost::fusion::traits::is_sequence<FS>::type::value>::type emplace_back_from_tuple(
    Container& out,
    FusionSeq&& seq)
{
    boost::fusion::invoke_function_object(impl::emplace_back_t<Container>{out}, std::forward<FusionSeq>(seq));
}

template <class Container, class Arg, class AA = typename std::remove_reference<Arg>::type>
inline typename std::enable_if<!boost::fusion::traits::is_sequence<AA>::type::value>::type emplace_back_from_tuple(
    Container& out,
    Arg&& arg)
{
    out.emplace_back(std::forward<Arg>(arg));
}
} // namespace tuple
} // namespace xzr

namespace xzr
{
namespace tuple
{
namespace impl
{
template <class A, class Tuple>
inline auto make_from_tuple(Tuple&& tuple, boost::mpl::false_)
{
    return boost::mp11::construct_from_tuple<A>(std::forward<Tuple>(tuple));
}

template <class A, class Tuple>
inline auto make_from_tuple(Tuple&& tuple, boost::mpl::true_)
{
    boost::value_factory<A> factory{};
    return boost::fusion::invoke_function_object(factory, std::forward<Tuple>(tuple));
}
} // namespace impl
template <class A,
          class Tuple,
          class TT = typename std::remove_reference<Tuple>::type,
          class IsFusionSeq = typename boost::fusion::traits::is_sequence<TT>::type>
inline auto make_from_tuple(Tuple&& tuple)
{
    return impl::make_from_tuple<A>(std::forward<Tuple>(tuple), IsFusionSeq{});
}
} // namespace tuple
} // namespace xzr

namespace xzr
{
namespace tuple
{
namespace impl
{
template <std::size_t N, class Tuple, std::size_t... Is>
inline constexpr auto drop_front(Tuple&& a, boost::mp11::index_sequence<Is...>)
    -> decltype(boost::fusion::as_nview<Is...>(a))
{
    return boost::fusion::as_nview<Is...>(a);
}
} // namespace impl

template <std::size_t N, class Tuple, class TT = typename std::remove_reference<Tuple>::type>
inline constexpr auto drop_front(Tuple&& a)
    -> decltype(impl::drop_front<N>(a, xzr::utility::make_index_range<N, boost::fusion::tuple_size<TT>::value>()))
{
    return impl::drop_front<N>(a, xzr::utility::make_index_range<N, boost::fusion::tuple_size<TT>::value>());
}
} // namespace tuple
} // namespace xzr

namespace xzr
{
namespace tuple
{
namespace impl
{
template <std::size_t N, class Tuple, std::size_t... Is>
inline constexpr auto take_front(Tuple&& a, boost::mp11::index_sequence<Is...>)
    -> decltype(boost::fusion::as_nview<Is...>(a))
{
    return boost::fusion::as_nview<Is...>(a);
}
} // namespace impl

template <std::size_t N, class Tuple, class TT = typename std::remove_reference<Tuple>::type>
inline constexpr auto take_front(Tuple&& a) -> decltype(impl::take_front<N>(a, boost::mp11::make_index_sequence<N>()))
{
    return impl::take_front<N>(a, boost::mp11::make_index_sequence<N>());
}
} // namespace tuple
} // namespace xzr

namespace xzr
{
namespace tuple
{
namespace impl
{
template <std::size_t N, class Tuple, std::size_t... Is>
inline constexpr auto replace_at(Tuple&& a, Tuple&& b, boost::mp11::index_sequence<Is...> idxs)
    -> decltype(boost::fusion::join(boost::fusion::join(xzr::tuple::take_front<N>(a),
                                                        boost::fusion::as_nview<(N + Is)...>(b)),
                                    xzr::tuple::drop_front<N + sizeof...(Is)>(a)))
{
    return boost::fusion::join(
        boost::fusion::join(xzr::tuple::take_front<N>(a), boost::fusion::as_nview<(N + Is)...>(b)),
        xzr::tuple::drop_front<N + sizeof...(Is)>(a));
}
} // namespace impl

template <std::size_t N, std::size_t Width, class Tuple, class TT = typename std::remove_reference<Tuple>::type>
inline constexpr auto replace_at(Tuple&& a, Tuple&& b)
    -> decltype(impl::replace_at<N>(a, b, boost::mp11::make_index_sequence<Width>{}))
{
    static_assert((N + Width) <= boost::fusion::tuple_size<TT>::value, "index + width is bigger than size of tuple");
    return impl::replace_at<N>(a, b, boost::mp11::make_index_sequence<Width>{});
}

template <std::size_t N, class Tuple>
inline constexpr auto replace_at(Tuple&& a, Tuple&& b) -> decltype(replace_at<N, 1>(a, b))
{
    return replace_at<N, 1>(a, b);
}
} // namespace tuple
} // namespace xzr

namespace xzr
{
namespace tuple
{
namespace impl
{
template <std::size_t Width, class Tuple, class OutIter, std::size_t... Is>
inline constexpr auto slide_window_c(Tuple&& a, Tuple&& b, OutIter out, boost::mp11::index_sequence<Is...>) -> void
{
    int dummy[] = {0, ((*out++ = xzr::tuple::replace_at<Is, Width>(a, b)), 0)...};
    static_cast<void>(dummy);
}
} // namespace impl

template <std::size_t Width, class Tuple, class OutIter, class TT = typename std::remove_reference<Tuple>::type>
inline constexpr auto slide_window(Tuple&& a, Tuple&& b, OutIter out) -> void
{
    constexpr auto tuple_size{boost::fusion::tuple_size<TT>::value};
    static_assert(Width <= tuple_size, "width shall not be greater than size of tuple");
    impl::slide_window_c<Width>(a, b, out, boost::mp11::make_index_sequence<tuple_size - Width + 1>{});
}

template <class Tuple, class OutIter, class TT = typename std::remove_reference<Tuple>::type>
inline constexpr auto slide_window(Tuple&& a, Tuple&& b, OutIter out) -> void
{
    slide_window<1>(a, b, out);
}
} // namespace tuple
} // namespace xzr


text:
//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================

#include "smtk/io/ModelToMesh.h"
#include "smtk/io/WriteMesh.h"
#include "smtk/io/ImportMesh.h"
#include "smtk/io/ExportJSON.h"
#include "smtk/io/ImportJSON.h"

#include "smtk/mesh/Collection.h"
#include "smtk/mesh/Manager.h"

#include "smtk/model/Manager.h"
#include "smtk/model/Volume.h"
#include "smtk/model/EntityIterator.h"

#include "smtk/model/testing/cxx/helpers.h"
#include "smtk/mesh/testing/cxx/helpers.h"

//force to use filesystem version 3
#define BOOST_FILESYSTEM_VERSION 3
#include <boost/filesystem.hpp>
using namespace boost::filesystem;

namespace
{
//SMTK_DATA_DIR is a define setup by cmake
std::string data_root = SMTK_DATA_DIR;
std::string write_root = data_root + "/mesh/tmp";

void cleanup( const std::string& file_path )
{
  //first verify the file exists
  ::boost::filesystem::path path( file_path );
  if( ::boost::filesystem::is_regular_file( path ) )
    {
    //remove the file_path if it exists.
    ::boost::filesystem::remove( path );
    }
}

//----------------------------------------------------------------------------
void create_simple_model( smtk::model::ManagerPtr mgr )
{
  std::size_t numTetsInModel = 4;
  using namespace smtk::model::testing;

  smtk::model::SessionRef sess = mgr->createSession("native");
  smtk::model::Model model = mgr->addModel();

  for(std::size_t i=0; i < numTetsInModel; ++i)
    {
    smtk::common::UUIDArray uids = createTet(mgr);
    model.addCell( smtk::model::Volume(mgr, uids[21]));
    }
  model.setSession(sess);
  mgr->assignDefaultNames();

}

//----------------------------------------------------------------------------
void verify_writing_and_loading_collection()
{
  std::string write_path(write_root);
  write_path += "/output.h5m";

  smtk::model::ManagerPtr modelManager = smtk::model::Manager::create();
  smtk::mesh::ManagerPtr meshManager = modelManager->meshes();

  create_simple_model(modelManager);

  smtk::io::ModelToMesh convert;
  smtk::mesh::CollectionPtr c = convert(meshManager,modelManager);
  smtk::common::UUID cUUID = c->entity();
  smtk::common::UUIDArray associations = c->meshes().modelEntityIds();

  cJSON* top = cJSON_CreateObject();
  c->writeLocation(write_path);
  const bool exportGood = smtk::io::ExportJSON::fromModelManager(top, modelManager);

  test(exportGood == 1, "Failed to export the mesh collections related to the model");

  //now remove the collection
  meshManager->removeCollection(c);
  test(meshManager->collection(cUUID) == NULL);
  c.reset(); //actually remove the collection from memory

  //now import collection from json stream
  const bool importGood = smtk::io::ImportJSON::ofMeshesOfModel(top,modelManager);
  test(importGood == 0, "Failed to import the mesh collections related to the model");

  //before we verify if the write was good, first remove the output file(s)
  cleanup( write_path );

  //verify collection uuid is the same.
  smtk::mesh::CollectionPtr c2 = meshManager->collection(cUUID);
  test(c2 != NULL,
       "Collection UUID can't change when being loaded from JSON");

  test( c2->modelManager()  == modelManager,
        "Collection loaded from JSON should be related to the model Manager");

  smtk::common::UUIDArray associations2 = c2->meshes().modelEntityIds();
  //most likely failing as we are not saving out custom tags?
  test( associations == associations2,
        "associations after loading from JSON should be the same" );

  test( meshManager->collectionsWithAssociations().size() == 1);
}

//----------------------------------------------------------------------------
void verify_writing_and_loading_multiple_collections()
{
  std::string write_path(write_root);
  std::string write_path2(write_root);

  write_path += "/output1.h5m";
  write_path2 += "/output2.h5m";

  smtk::model::ManagerPtr modelManager = smtk::model::Manager::create();
  smtk::mesh::ManagerPtr meshManager = modelManager->meshes();

  create_simple_model(modelManager);

  smtk::io::ModelToMesh convert;
  smtk::mesh::CollectionPtr c = convert(meshManager,modelManager);
  smtk::mesh::CollectionPtr c2 = convert(meshManager,modelManager);

  cJSON* top = cJSON_CreateObject();
  c->writeLocation(write_path);
  c2->writeLocation(write_path2);
  const bool exportGood = smtk::io::ExportJSON::fromModelManager(top, modelManager);

  test(exportGood == 1, "Failed to export the mesh collections related to the model");

  //now remove the collection
  meshManager->removeCollection(c);
  meshManager->removeCollection(c2);
  c.reset();
  c2.reset();

  //now import collection from json stream
  const bool importGood = smtk::io::ImportJSON::ofMeshesOfModel(top,modelManager);

  //before we verify if the write was good, first remove the output file(s)
  cleanup( write_path );
  cleanup( write_path2 );

  test(importGood == 0, "Failed to import the mesh collections related to the model");

  test(meshManager->numberOfCollections() == 2, "number of collections incorrect");

  std::vector<smtk::mesh::CollectionPtr> collections =
                            meshManager->collectionsWithAssociations();
  test(collections.size() == 2, "number of collections with associations incorrect");
}

//----------------------------------------------------------------------------
void verify_writing_and_loading_collections_without_file_path()
{
  std::string write_path(write_root);
  write_path += "/output1.h5m";

  smtk::model::ManagerPtr modelManager = smtk::model::Manager::create();
  smtk::mesh::ManagerPtr meshManager = modelManager->meshes();

  create_simple_model(modelManager);

  smtk::io::ModelToMesh convert;
  smtk::mesh::CollectionPtr c = convert(meshManager,modelManager);
  smtk::mesh::CollectionPtr c2 = convert(meshManager,modelManager);

  c->name("fileBased");
  c->writeLocation(write_path);

  c2->name("jsonBased");

  cJSON* top = cJSON_CreateObject();

  const bool exportGood = smtk::io::ExportJSON::fromModelManager(top, modelManager);
  test(exportGood == 1, "Failed to export the mesh collections related to the model");

  //now remove the collection
  meshManager->removeCollection(c);
  meshManager->removeCollection(c2);
  c.reset();
  c2.reset();
  test(meshManager->numberOfCollections() == 0, "number of collections incorrect");

  //now import collection from json stream
  const bool importGood = smtk::io::ImportJSON::ofMeshesOfModel(top,modelManager);

  //before we verify if the write was good, first remove the output file(s)
  cleanup( write_path );

  test(importGood == 0, "Failed to import the mesh collections related to the model");

  test(meshManager->numberOfCollections() == 2, "number of collections incorrect");

  std::vector<smtk::mesh::CollectionPtr> collections =
                            meshManager->collectionsWithAssociations();
  test(collections.size() == 2, "number of collections with associations incorrect");

  //next verify that both collections have valid names
  std::vector< std::string > names;
  names.push_back( collections[0]->name() );
  names.push_back( collections[1]->name() );
  std::sort(names.begin(), names.end());

  test( (names[0]==std::string("fileBased")), "Name doesn't match name during export");
  test( (names[1]==std::string("jsonBased")), "Name doesn't match name during export");

}

//----------------------------------------------------------------------------
void verify_writing_of_single_collection_to_disk()
{
  std::string file_path(data_root);
  file_path += "/mesh/twoassm_out.h5m";

  std::string write_path(write_root);
  write_path += "/output.h5m";

  smtk::mesh::ManagerPtr manager = smtk::mesh::Manager::create();
  smtk::mesh::CollectionPtr c = smtk::io::ImportMesh::entireFile(file_path, manager);
  test( c->isValid(), "collection should be valid");

  std::size_t numMeshes = c->numberOfMeshes();
  test( numMeshes!=0, "dataset once loaded should have more than zero meshes");
  test( numMeshes == 53, "dataset once loaded should have 53 meshes");

  //add some fake boundary conditions
  c->meshes( smtk::mesh::Domain(444) ).setDirichlet( smtk::mesh::Dirichlet(2) );
  c->meshes( smtk::mesh::Domain(444) ).setNeumann( smtk::mesh::Neumann(3) );
  c->meshes( smtk::mesh::Domain(446) ).setNeumann( smtk::mesh::Neumann(2) );

  //verify that we can write this out even when we have no model associations
  //by using forSingleCollection
  c->writeLocation( write_path );
  cJSON* top = cJSON_CreateObject();
  const bool exportGood = smtk::io::ExportJSON::forSingleCollection(top, c);

  test(exportGood == 1, "Expected the Export of forSingleCollection to pass");
}

//----------------------------------------------------------------------------
void verify_writing_of_single_collection_to_json()
{
  std::string file_path(data_root);
  file_path += "/mesh/twoassm_out.h5m";

  smtk::mesh::ManagerPtr manager = smtk::mesh::Manager::create();
  smtk::mesh::CollectionPtr c = smtk::io::ImportMesh::entireFile(file_path, manager);
  test( c->isValid(), "collection should be valid");

  std::size_t numMeshes = c->numberOfMeshes();
  test( numMeshes!=0, "dataset once loaded should have more than zero meshes");
  test( numMeshes == 53, "dataset once loaded should have 53 meshes");

  //add some fake boundary conditions
  c->meshes( smtk::mesh::Domain(444) ).setDirichlet( smtk::mesh::Dirichlet(2) );
  c->meshes( smtk::mesh::Domain(444) ).setNeumann( smtk::mesh::Neumann(3) );
  c->meshes( smtk::mesh::Domain(446) ).setNeumann( smtk::mesh::Neumann(2) );

  cJSON* top = cJSON_CreateObject();
  const bool exportGood = smtk::io::ExportJSON::forSingleCollection(top, c);

  test(exportGood == 1, "Expected the Export of forSingleCollection to pass");
}

//----------------------------------------------------------------------------
void verify_reading_of_single_collection_from_json()
{
  std::string file_path(data_root);
  file_path += "/mesh/twoassm_out.h5m";

  smtk::mesh::ManagerPtr manager = smtk::mesh::Manager::create();
  cJSON* top = cJSON_CreateObject();

  {
  smtk::mesh::CollectionPtr c = smtk::io::ImportMesh::entireFile(file_path, manager);
  test( c->isValid(), "collection should be valid");

  std::size_t numMeshes = c->numberOfMeshes();
  test( numMeshes != 0, "dataset once loaded should have more than zero meshes");
  test( numMeshes == 53, "dataset once loaded should have 53 meshes");

  //add some fake boundary conditions
  c->meshes( smtk::mesh::Domain(444) ).setDirichlet( smtk::mesh::Dirichlet(2) );
  c->meshes( smtk::mesh::Domain(444) ).setNeumann( smtk::mesh::Neumann(3) );
  c->meshes( smtk::mesh::Domain(446) ).setNeumann( smtk::mesh::Neumann(2) );

  const bool exportGood = smtk::io::ExportJSON::forSingleCollection(top, c);

  test(exportGood == 1, "Expected the Export of forSingleCollection to pass");

  manager->removeCollection(c);
  }

  //now import collection from json stream
  {
  //get the first child node which is a collection
  cJSON* collection = top->child;
  smtk::mesh::CollectionPtr c = smtk::io::ImportMesh::entireJSON(collection, manager);

  std::size_t numMeshes = c->numberOfMeshes();
  test( numMeshes != 0, "dataset once loaded should have more than zero meshes");
  test( numMeshes == 53, "dataset once loaded should have 53 meshes");

  //verify domains work
  smtk::mesh::MeshSet domain = c->meshes( smtk::mesh::Domain(444) );
  test( domain.size() == 1, "wrong number of domains loaded from json");

  //verify boundary condtions
  smtk::mesh::MeshSet dMeshes = c->meshes( smtk::mesh::Dirichlet(2) );
  smtk::mesh::MeshSet nMeshes = c->meshes( smtk::mesh::Neumann(2) );
  nMeshes.append( c->meshes( smtk::mesh::Neumann(3) ) );

  //verify not empty
  test( dMeshes.is_empty() == false, "wrong number of Dirichlet loaded from json");
  test( nMeshes.is_empty() == false, "wrong number of Neumann loaded from json");

  //verify correct size
  test( dMeshes.size() == 1, "wrong number of dirichlet sets");
  test( nMeshes.size() == 2, "wrong number of neumann sets");
  }

}

//----------------------------------------------------------------------------
void verify_loading_existing_collection_fails()
{
  std::string write_path(write_root);
  write_path += "/output.h5m";

  smtk::model::ManagerPtr modelManager = smtk::model::Manager::create();
  smtk::mesh::ManagerPtr meshManager = modelManager->meshes();

  create_simple_model(modelManager);

  smtk::io::ModelToMesh convert;
  smtk::mesh::CollectionPtr c = convert(meshManager,modelManager);
  smtk::common::UUID cUUID = c->entity();

  cJSON* top = cJSON_CreateObject();
  c->writeLocation(write_path);
  const bool exportGood = smtk::io::ExportJSON::fromModelManager(top, modelManager);

  test(exportGood == 1, "Failed to export the mesh collections related to the model");

  const std::size_t numberOfCollections = meshManager->numberOfCollections();
  //now import collection from json stream, should fail as the collection
  //hasn't been removed
  const bool importGood = smtk::io::ImportJSON::ofMeshesOfModel(top,modelManager);

  //before we verify if the write was good, first remove the output file(s)
  cleanup( write_path );

  test(importGood == 0, "Import of mesh was supposed to fail");
  test(numberOfCollections == meshManager->numberOfCollections(),
       "Importing existing collections should not change the number of collections");
}

}

//----------------------------------------------------------------------------
int UnitTestReadWriteMeshJSON(int, char** const)
{
  verify_writing_and_loading_collection();
  verify_writing_and_loading_multiple_collections();
  verify_writing_and_loading_collections_without_file_path();

  verify_writing_of_single_collection_to_disk();
  verify_writing_of_single_collection_to_json();

  verify_reading_of_single_collection_from_json();

  verify_loading_existing_collection_fails();

  return 0;
}

ext: cxx

max_stars_repo_name: yumin/SMTK

max_issues_repo_name: yumin/SMTK

max_forks_repo_name: yumin/SMTK