<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#ifndef NIX_SECTION_H
#define NIX_SECTION_H

#include <nix/util/filter.hpp>
#include <nix/base/NamedEntity.hpp>
#include <nix/base/ISection.hpp>
#include <nix/Property.hpp>
#include <nix/DataType.hpp>
#include <nix/Platform.hpp>
#include <nix/types.hpp>
#include <memory>
#include <functional>
#include <string>
#include <cstdlib>

namespace nix {

class NIXAPI Section : public base::NamedEntity<base::ISection> {

public:

    /**
     * @brief Constructor that creates an uninitialized Section.
     *
     * Calling any method on an uninitialized section will throw a {@link nix::UninitializedEntity}
     * exception. The following code illustrates how to check if a section is initialized:
     *
     * ~~~
     * Section e = ...;
     * if (e) {
     *     // e is initialised
     * } else {
     *     // e is uninitialized
     * }
     * ~~~
     */
    Section();

    /**
     * @brief Constructor that creates a null Section.
     */
    Section(std::nullptr_t ptr);

    /**
     * @brief Copy constructor.
     *
     * Copying of all NIX front facing objects like Section is a rather cheap operation.
     * Semantically this is equivalent to the creation of another reference to the original
     * object.
     *
     * @param other     The Section to copy.
     */
    Section(const Section &other);

    /**
     * @brief Constructor that creates a new Section from a shared pointer to
     * an implementation instance.
     *
     * This constructor should only be used in the back-end.
     */
    Section(const std::shared_ptr<base::ISection> &p_impl);

    /**
     * @brief Constructor with move semantics that creates a new Section from a shared pointer to
     * an implementation instance.
     *
     * This constructor should only be used in the back-end.
     */
    Section(std::shared_ptr<base::ISection> &&ptr);

    //--------------------------------------------------
    // Attribute getter and setter
    //--------------------------------------------------

    /**
     * @brief Set the repository in which a section of this type is defined.
     *
     * Usually this information is provided in the form of an URL
     *
     * @param repository        URL to the repository.
     */
    void repository(const std::string &repository);

    /**
     * @brief Gets the repository URL.
     *
     * @return The URL to the repository.
     */
    boost::optional<std::string> repository() const {
        return backend()->repository();
    }

    /**
     * @brief Deleter for the repository.
     *
     * @param t         None
     */
    void repository(const boost::none_t t) {
        backend()->repository(t);
    }

    /**
     * @brief Establish a link to another section.
     *
     * The linking section inherits the properties defined in the linked section.
     * Properties of the same name are overridden.
     *
     * @param id        The id of the section that should be linked.
     */
    void link(const std::string &id);

    /**
     * @brief Establish a link to another section.
     *
     * The linking section inherits the properties defined in the linked section.
     * Properties of the same name are overridden.
     *
     * @param link      The section to link with.
     */
    void link(const Section &link);

    /**
     * @brief Get the linked section.
     *
     * @return The linked section. If no section was linked a null
     *         Section will be returned.
     */
    Section link() const {
        return backend()->link();
    }

    /**
     * @brief Deleter for the linked section.
     *
     * This just removes the link between both sections, but does not remove
     * the linked section from the file.
     *
     * @param t         None
     */
    void link(const boost::none_t t) {
        backend()->link(t);
    }

    /**
     * @brief Sets the mapping information for this section.
     *
     * The mapping is provided as a path or URL to another section.
     *
     * @param mapping   The mapping information to this section.
     */
    void mapping(const std::string &mapping);

    /**
     * @brief Gets the mapping information.
     *
     * @return The mapping information.
     */
    boost::optional<std::string> mapping() const {
        return backend()->mapping();
    }

    /**
     * @brief Deleter for the mapping information.
     *
     * @param t         None
     */
    void mapping(const boost::none_t t) {
        backend()->mapping(t);
    }

    //--------------------------------------------------
    // Methods for parent access
    //--------------------------------------------------

    /**
     * @brief Returns the parent section.
     *
     * Each section which is not a root section has a parent.
     *
     * @return The parent section. If the section has no parent, a null
     *         section will be returned.
     */
    Section parent() const {
        return backend()->parent();
    }

    //--------------------------------------------------
    // Methods for child section access
    //--------------------------------------------------

    /**
     * @brief Get the number of child section of the section.
     *
     * @return The number of child sections.
     */
    ndsize_t sectionCount() const {
        return backend()->sectionCount();
    }

    /**
     * @brief Checks whether a section has a certain child section.
     *
     * @param name_or_id        Name or id of requested section.
     *
     * @return True if the section is a child, false otherwise.
     */
    bool hasSection(const std::string &name_or_id) const {
        return backend()->hasSection(name_or_id);
    }

    /**
     * @brief Checks whether a section has a certain child section.
     *
     * @param section   The section to check.
     *
     * @return True if the section is a child, false otherwise.
     */
    bool hasSection(const Section &section) const;

    /**
     * @brief Get a specific child section by its name or id.
     *
     * @param name_or_id  The name or the ID of the child section.
     *
     * @return The child section.
     */
    Section getSection(const std::string &name_or_id) const {
        return backend()->getSection(name_or_id);
    }

    /**
     * @brief Get a child section by its index.
     *
     * @param index     The index of the child.
     *
     * @return The specified child section.
     */
    virtual Section getSection(ndsize_t index) const;

    /**
     * @brief Get all direct child sections of the section.
     *
     * The parameter filter can be used to filter sections by various
     * criteria. By default a filter is used that accepts all sections.
     *
     * @param filter    A filter function.
     *
     * @return A vector containing the matching child sections.
     */
    std::vector<Section> sections(const util::Filter<Section>::type &filter = util::AcceptAll<Section>()) const;

    /**
     * @brief Get all descendant sections of the section recursively.
     *
     * This method traverses the sub-tree of all child sections of the section. The traversal
     * is accomplished via breadth first and can be limited in depth. On each node or
     * section a filter is applied. If the filter returns true the respective section
     * will be added to the result list.
     * By default a filter is used that accepts all sections.
     *
     * @param filter       A filter function.
     * @param max_depth    The maximum depth of traversal.
     *
     * @return A vector containing the matching descendant sections.
     */
    std::vector<Section> findSections(const util::Filter<Section>::type &filter = util::AcceptAll<Section>(),
                                      size_t max_depth = std::numeric_limits<size_t>::max()) const;

    /**
     * @brief Find all related sections of the section.
     *
     * @param filter       A filter function.
     *
     * @return A vector containing all filtered related sections.
     */
    std::vector<Section> findRelated(const util::Filter<Section>::type &filter = util::AcceptAll<Section>()) const;

    /**
     *  @brief Adds a new child section.
     *
     *  @param name     The name of the new section
     *  @param type     The type of the section
     *
     *  @return The new child section.
     */
    Section createSection(const std::string &name, const std::string &type);

    /**
     * @brief Deletes a section from the section.
     *
     * @param name_or_id        Name or id of the child section to delete.
     *
     * @return True if the section was deleted, false otherwise.
     */
    bool deleteSection(const std::string &name_or_id) {
        return backend()->deleteSection(name_or_id);
    }

    /**
     * @brief Deletes a subsection from this Section.
     *
     * @param section   The section to delete.
     *
     * @return bool successful or not
     */
    bool deleteSection(const Section &section);

    //--------------------------------------------------
    // Methods for property access
    //--------------------------------------------------

    /**
     * @brief Gets the number of properties of this section.
     *
     * @return The number of Properties
     */
    ndsize_t propertyCount() const {
        return backend()->propertyCount();
    }

    /**
     * @brief Checks if a Property with this name/id exists in this Section.
     *
     * @param name_or_id    Name or id of the property.
     *
     * @return True if the property exists, false otherwise.
     */
    bool hasProperty(const std::string &name_or_id) const {
        return backend()->hasProperty(name_or_id);
    }

    /**
     * @brief Checks if a Property exists in this Section.
     *
     * @param property      The Property to check.
     *
     * @return True if the property exists, false otherwise.
     */
    bool hasProperty(const Property &property) const;

    /**
     * @brief Gets the Property identified by its name or id.
     *
     * @param name_or_id    Name or id of the property.
     *
     * @return The specified property.
     */
    Property getProperty(const std::string &name_or_id) const {
        return backend()->getProperty(name_or_id);
    }

    /**
     * @brief Gets the property defined by its index.
     *
     * @param index     The index of the property
     *
     * @return The property.
     */
    Property getProperty(ndsize_t index) const {
        return backend()->getProperty(index);
    }

    /**
     * @brief Get all properties of the section.
     *
     * The parameter filter can be used to filter properties by various
     * criteria. By default a filter is used that accepts all properties.
     *
     * @param filter    A filter function.
     *
     * @return A vector containing the matching properties.
     */
    std::vector<Property> properties(const util::Filter<Property>::type &filter=util::AcceptAll<Property>()) const;

    /**
     * Returns all Properties inherited from a linked section.
     * This list may include Properties that are locally overridden.
     *
     * @return All inherited properties as a vector.
     */
    std::vector<Property> inheritedProperties() const;

    /**
     * @brief Add a new Property that does not have any Values to this Section.
     *
     * @param name     The name of the property.
     * @param dtype    The DataType of the property.
     *
     * @return The newly created property
     */
    Property createProperty(const std::string &name, const DataType &dtype);

    /**
     * @brief Add a new Property to the Section.
     *
     * @param name      The name of the property.
     * @param value     The Value to be stored.
     *
     * @return The newly created property.
     */
    Property createProperty(const std::string &name, const Value &value);

    /**
     * @brief Add a new Property with values to the Section.
     *
     * @param name      The name of the property.
     * @param values    The values of the created property.
     *
     * @return The newly created property.
     */
    Property createProperty(const std::string &name, const std::vector<Value> &values);

    /**
     * @brief Delete the Property identified by its name or id.
     *
     * @param name_or_id    Name or id of the property.
     *
     * @return True if the property was deleted, false otherwise.
     */
    bool deleteProperty(const std::string &name_or_id) {
        return backend()->deleteProperty(name_or_id);
    }

    /**
     * @brief Deletes the Property from this section.
     *
     * @param property      The Property to delete.
     *
     * @return True if the property was deleted, false otherwise.
     */
    bool deleteProperty(const Property &property);

    //--------------------------------------------------
    // Other methods and functions
    //--------------------------------------------------

    std::vector<nix::DataArray> referringDataArrays(const nix::Block &b) const;

    std::vector<nix::DataArray> referringDataArrays() const;

    std::vector<nix::Tag> referringTags() const;

    std::vector<nix::Tag> referringTags(const nix::Block &b) const;

    std::vector<nix::MultiTag> referringMultiTags() const;

    std::vector<nix::MultiTag> referringMultiTags(const nix::Block &b) const;

    std::vector<nix::Source> referringSources() const;

    std::vector<nix::Source> referringSources(const nix::Block &b) const;

    std::vector<nix::Block> referringBlocks() const;

    /**
     * @brief Assignment operator for none.
     */
    Section &operator=(const none_t &t) {
        ImplContainer::operator=(t);
        return *this;
    }

    /**
     * @brief Output operator
     */
    NIXAPI friend std::ostream& operator<<(std::ostream &out, const Section &ent);

private:

    std::vector<Section> findDownstream(const std::function<bool(Section)> &filter) const;

    std::vector<Section> findUpstream(const std::function<bool(Section)> &filter) const;

    std::vector<Section> findSideways(const std::function<bool(Section)> &filter, const std::string &caller_id) const;

    size_t tree_depth() const;
};

} // namespace nix

#endif // NIX_SECTION_H
<commit_msg>[Section] add docstrings<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#ifndef NIX_SECTION_H
#define NIX_SECTION_H

#include <nix/util/filter.hpp>
#include <nix/base/NamedEntity.hpp>
#include <nix/base/ISection.hpp>
#include <nix/Property.hpp>
#include <nix/DataType.hpp>
#include <nix/Platform.hpp>
#include <nix/types.hpp>
#include <memory>
#include <functional>
#include <string>
#include <cstdlib>

namespace nix {

class NIXAPI Section : public base::NamedEntity<base::ISection> {

public:

    /**
     * @brief Constructor that creates an uninitialized Section.
     *
     * Calling any method on an uninitialized section will throw a {@link nix::UninitializedEntity}
     * exception. The following code illustrates how to check if a section is initialized:
     *
     * ~~~
     * Section e = ...;
     * if (e) {
     *     // e is initialised
     * } else {
     *     // e is uninitialized
     * }
     * ~~~
     */
    Section();

    /**
     * @brief Constructor that creates a null Section.
     */
    Section(std::nullptr_t ptr);

    /**
     * @brief Copy constructor.
     *
     * Copying of all NIX front facing objects like Section is a rather cheap operation.
     * Semantically this is equivalent to the creation of another reference to the original
     * object.
     *
     * @param other     The Section to copy.
     */
    Section(const Section &other);

    /**
     * @brief Constructor that creates a new Section from a shared pointer to
     * an implementation instance.
     *
     * This constructor should only be used in the back-end.
     */
    Section(const std::shared_ptr<base::ISection> &p_impl);

    /**
     * @brief Constructor with move semantics that creates a new Section from a shared pointer to
     * an implementation instance.
     *
     * This constructor should only be used in the back-end.
     */
    Section(std::shared_ptr<base::ISection> &&ptr);

    //--------------------------------------------------
    // Attribute getter and setter
    //--------------------------------------------------

    /**
     * @brief Set the repository in which a section of this type is defined.
     *
     * Usually this information is provided in the form of an URL
     *
     * @param repository        URL to the repository.
     */
    void repository(const std::string &repository);

    /**
     * @brief Gets the repository URL.
     *
     * @return The URL to the repository.
     */
    boost::optional<std::string> repository() const {
        return backend()->repository();
    }

    /**
     * @brief Deleter for the repository.
     *
     * @param t         None
     */
    void repository(const boost::none_t t) {
        backend()->repository(t);
    }

    /**
     * @brief Establish a link to another section.
     *
     * The linking section inherits the properties defined in the linked section.
     * Properties of the same name are overridden.
     *
     * @param id        The id of the section that should be linked.
     */
    void link(const std::string &id);

    /**
     * @brief Establish a link to another section.
     *
     * The linking section inherits the properties defined in the linked section.
     * Properties of the same name are overridden.
     *
     * @param link      The section to link with.
     */
    void link(const Section &link);

    /**
     * @brief Get the linked section.
     *
     * @return The linked section. If no section was linked a null
     *         Section will be returned.
     */
    Section link() const {
        return backend()->link();
    }

    /**
     * @brief Deleter for the linked section.
     *
     * This just removes the link between both sections, but does not remove
     * the linked section from the file.
     *
     * @param t         None
     */
    void link(const boost::none_t t) {
        backend()->link(t);
    }

    /**
     * @brief Sets the mapping information for this section.
     *
     * The mapping is provided as a path or URL to another section.
     *
     * @param mapping   The mapping information to this section.
     */
    void mapping(const std::string &mapping);

    /**
     * @brief Gets the mapping information.
     *
     * @return The mapping information.
     */
    boost::optional<std::string> mapping() const {
        return backend()->mapping();
    }

    /**
     * @brief Deleter for the mapping information.
     *
     * @param t         None
     */
    void mapping(const boost::none_t t) {
        backend()->mapping(t);
    }

    //--------------------------------------------------
    // Methods for parent access
    //--------------------------------------------------

    /**
     * @brief Returns the parent section.
     *
     * Each section which is not a root section has a parent.
     *
     * @return The parent section. If the section has no parent, a null
     *         section will be returned.
     */
    Section parent() const {
        return backend()->parent();
    }

    //--------------------------------------------------
    // Methods for child section access
    //--------------------------------------------------

    /**
     * @brief Get the number of child section of the section.
     *
     * @return The number of child sections.
     */
    ndsize_t sectionCount() const {
        return backend()->sectionCount();
    }

    /**
     * @brief Checks whether a section has a certain child section.
     *
     * @param name_or_id        Name or id of requested section.
     *
     * @return True if the section is a child, false otherwise.
     */
    bool hasSection(const std::string &name_or_id) const {
        return backend()->hasSection(name_or_id);
    }

    /**
     * @brief Checks whether a section has a certain child section.
     *
     * @param section   The section to check.
     *
     * @return True if the section is a child, false otherwise.
     */
    bool hasSection(const Section &section) const;

    /**
     * @brief Get a specific child section by its name or id.
     *
     * @param name_or_id  The name or the ID of the child section.
     *
     * @return The child section.
     */
    Section getSection(const std::string &name_or_id) const {
        return backend()->getSection(name_or_id);
    }

    /**
     * @brief Get a child section by its index.
     *
     * @param index     The index of the child.
     *
     * @return The specified child section.
     */
    virtual Section getSection(ndsize_t index) const;

    /**
     * @brief Get all direct child sections of the section.
     *
     * The parameter filter can be used to filter sections by various
     * criteria. By default a filter is used that accepts all sections.
     *
     * @param filter    A filter function.
     *
     * @return A vector containing the matching child sections.
     */
    std::vector<Section> sections(const util::Filter<Section>::type &filter = util::AcceptAll<Section>()) const;

    /**
     * @brief Get all descendant sections of the section recursively.
     *
     * This method traverses the sub-tree of all child sections of the section. The traversal
     * is accomplished via breadth first and can be limited in depth. On each node or
     * section a filter is applied. If the filter returns true the respective section
     * will be added to the result list.
     * By default a filter is used that accepts all sections.
     *
     * @param filter       A filter function.
     * @param max_depth    The maximum depth of traversal.
     *
     * @return A vector containing the matching descendant sections.
     */
    std::vector<Section> findSections(const util::Filter<Section>::type &filter = util::AcceptAll<Section>(),
                                      size_t max_depth = std::numeric_limits<size_t>::max()) const;

    /**
     * @brief Find all related sections of the section.
     *
     * @param filter       A filter function.
     *
     * @return A vector containing all filtered related sections.
     */
    std::vector<Section> findRelated(const util::Filter<Section>::type &filter = util::AcceptAll<Section>()) const;

    /**
     *  @brief Adds a new child section.
     *
     *  @param name     The name of the new section
     *  @param type     The type of the section
     *
     *  @return The new child section.
     */
    Section createSection(const std::string &name, const std::string &type);

    /**
     * @brief Deletes a section from the section.
     *
     * @param name_or_id        Name or id of the child section to delete.
     *
     * @return True if the section was deleted, false otherwise.
     */
    bool deleteSection(const std::string &name_or_id) {
        return backend()->deleteSection(name_or_id);
    }

    /**
     * @brief Deletes a subsection from this Section.
     *
     * @param section   The section to delete.
     *
     * @return bool successful or not
     */
    bool deleteSection(const Section &section);

    //--------------------------------------------------
    // Methods for property access
    //--------------------------------------------------

    /**
     * @brief Gets the number of properties of this section.
     *
     * @return The number of Properties
     */
    ndsize_t propertyCount() const {
        return backend()->propertyCount();
    }

    /**
     * @brief Checks if a Property with this name/id exists in this Section.
     *
     * @param name_or_id    Name or id of the property.
     *
     * @return True if the property exists, false otherwise.
     */
    bool hasProperty(const std::string &name_or_id) const {
        return backend()->hasProperty(name_or_id);
    }

    /**
     * @brief Checks if a Property exists in this Section.
     *
     * @param property      The Property to check.
     *
     * @return True if the property exists, false otherwise.
     */
    bool hasProperty(const Property &property) const;

    /**
     * @brief Gets the Property identified by its name or id.
     *
     * @param name_or_id    Name or id of the property.
     *
     * @return The specified property.
     */
    Property getProperty(const std::string &name_or_id) const {
        return backend()->getProperty(name_or_id);
    }

    /**
     * @brief Gets the property defined by its index.
     *
     * @param index     The index of the property
     *
     * @return The property.
     */
    Property getProperty(ndsize_t index) const {
        return backend()->getProperty(index);
    }

    /**
     * @brief Get all properties of the section.
     *
     * The parameter filter can be used to filter properties by various
     * criteria. By default a filter is used that accepts all properties.
     *
     * @param filter    A filter function.
     *
     * @return A vector containing the matching properties.
     */
    std::vector<Property> properties(const util::Filter<Property>::type &filter=util::AcceptAll<Property>()) const;

    /**
     * Returns all Properties inherited from a linked section.
     * This list may include Properties that are locally overridden.
     *
     * @return All inherited properties as a vector.
     */
    std::vector<Property> inheritedProperties() const;

    /**
     * @brief Add a new Property that does not have any Values to this Section.
     *
     * @param name     The name of the property.
     * @param dtype    The DataType of the property.
     *
     * @return The newly created property
     */
    Property createProperty(const std::string &name, const DataType &dtype);

    /**
     * @brief Add a new Property to the Section.
     *
     * @param name      The name of the property.
     * @param value     The Value to be stored.
     *
     * @return The newly created property.
     */
    Property createProperty(const std::string &name, const Value &value);

    /**
     * @brief Add a new Property with values to the Section.
     *
     * @param name      The name of the property.
     * @param values    The values of the created property.
     *
     * @return The newly created property.
     */
    Property createProperty(const std::string &name, const std::vector<Value> &values);

    /**
     * @brief Delete the Property identified by its name or id.
     *
     * @param name_or_id    Name or id of the property.
     *
     * @return True if the property was deleted, false otherwise.
     */
    bool deleteProperty(const std::string &name_or_id) {
        return backend()->deleteProperty(name_or_id);
    }

    /**
     * @brief Deletes the Property from this section.
     *
     * @param property      The Property to delete.
     *
     * @return True if the property was deleted, false otherwise.
     */
    bool deleteProperty(const Property &property);

    //--------------------------------------------------
    // Other methods and functions
    //--------------------------------------------------

    /**
     * @brief Find the DataArrays that refer to this Section in the metadata field.
     *
     * @param b The Block in which the search should be performed.
     * @return Vector of DataArrays.
     */
    std::vector<nix::DataArray> referringDataArrays(const nix::Block &b) const;

    /**
     * @brief Find the DataArrays that refer to this Section in the metadata field.
     * Search is performed in the whole file.
     *
     * @return Vector of DataArrays.
     */
    std::vector<nix::DataArray> referringDataArrays() const;

    /**
     * @brief Find the Tags that refer to this Section in the metadata field.
     * Search is performed in the whole file.
     *
     * @return std::vector of Tags.
     */
    std::vector<nix::Tag> referringTags() const;

    /**
     * @brief Find the Tags that refer to this Section in the metadata field.
     *
     * @param b The Block in which the search should be performed.
     * @return std::vector of Tags.
     */
    std::vector<nix::Tag> referringTags(const nix::Block &b) const;

    /**
     * @brief Find the DataArrays that refer to this Section in the metadata field.
     * Search is performed in the whole file.
     *
     * @return std::vector of MultiTags.
     */
    std::vector<nix::MultiTag> referringMultiTags() const;

    /**
     * @brief Find the MultiTags that refer to this Section in the metadata field.
     *
     * @param b The Block in which the search should be performed.
     * @return std::vector of MultiTags.
     */
    std::vector<nix::MultiTag> referringMultiTags(const nix::Block &b) const;

    /**
     * @brief Find the Sources that refer to this Section in the metadata field.
     *
     * @param b The Block in which the search should be performed.
     * @return std::vector of Sources.
     */
    std::vector<nix::Source> referringSources() const;

    /**
     * @brief Find the Sources that refer to this Section in the metadata field.
     * Search is performed in the whole file.
     *
     * @return std::vector of Sources.
     */
    std::vector<nix::Source> referringSources(const nix::Block &b) const;

    /**
     * @brief Find the Blocks that refer to this Section in the metadata field.
     *
     * @return std::vector of Blocks.
     */
    std::vector<nix::Block> referringBlocks() const;

    /**
     * @brief Assignment operator for none.
     */
    Section &operator=(const none_t &t) {
        ImplContainer::operator=(t);
        return *this;
    }

    /**
     * @brief Output operator
     */
    NIXAPI friend std::ostream& operator<<(std::ostream &out, const Section &ent);

private:

    std::vector<Section> findDownstream(const std::function<bool(Section)> &filter) const;

    std::vector<Section> findUpstream(const std::function<bool(Section)> &filter) const;

    std::vector<Section> findSideways(const std::function<bool(Section)> &filter, const std::string &caller_id) const;

    size_t tree_depth() const;
};

} // namespace nix

#endif // NIX_SECTION_H
<|endoftext|>


<commit_before>#ifndef __QUEUE_HPP_INCLUDED__
#define __QUEUE_HPP_INCLUDED__

#include <cstdint>
#include <fstream>
#include <mutex>

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

#include "serialization.hpp"

namespace fs = boost::filesystem;

template <typename T>
class BaseQueue
{
private:

    virtual T getElementAt(int64_t index) = 0;

    virtual int64_t getElementSizeAt(int64_t index) = 0;

    virtual int64_t getFirstElementIndex() = 0;

    virtual int64_t getLastElementIndex() = 0;

    class Iterator
    {
    public:

        Iterator(BaseQueue<T> *queue_, int64_t index_)
            : queue(queue_), index(index_)
        {
        }

        T operator*()
        {
            return queue->getElementAt(index);
        }

        Iterator& operator++()
        {
            int64_t size = queue->getElementSizeAt(index);
            index += size;
            return *this;
        }

        bool operator!=(const Iterator& iterator)
        {
            return index != iterator.index;
        }

    private:

        BaseQueue<T> *queue;

        int64_t index;
    };

public:

    virtual void Enqueue(T e) = 0;

    virtual void Dequeue() = 0;

    virtual T Last() = 0;

    Iterator begin()
    {
        return Iterator(this, getFirstElementIndex());
    }

    Iterator end()
    {
        return Iterator(this, getLastElementIndex());
    }
};

template <typename T>
class VolatileQueue : public BaseQueue<T>
{
public:

    void Enqueue(T e)
    {
        data.push_back(e);
    }

    void Dequeue()
    {
        if (!data.empty())
        {
            data.erase(data.begin());
        }
    }

    T Last()
    {
        T empty;
        return data.size() > 0 ? data[data.size() - 1 ] : empty;
    }

private:

    T getElementAt(int64_t index)
    {
        return data[index];
    }

    int64_t getElementSizeAt(int64_t index)
    {
        return 1;
    }

    int64_t getFirstElementIndex()
    {
        return 0;
    }

    int64_t getLastElementIndex()
    {
        return data.size();
    }

    std::vector<T> data;
};

template <typename T>
class PersistentQueue : public BaseQueue<T>
{
public:

    PersistentQueue(std::string filename)
        : PersistentQueue(".", filename)
    {
    }

    PersistentQueue(std::string dirname, std::string filename)
        : file((fs::path(dirname) / fs::path(filename)).string(),
               std::ios::out | std::ios::in | std::ios::app | std::ios::binary),
          stream(file),
          insert_file((fs::path(dirname) / fs::path(filename)).string(),
                       std::ios::in | std::ios::out | std::ios::binary),
          insert_stream(insert_file),
          start_position(0),
          end_position(0),
          mutex()
    {
        SaveOffsets();
        LoadOffsets();
    }

    PersistentQueue(std::iostream& stream)
        : stream(stream),
          insert_stream(stream),
          start_position(0),
          end_position(0),
          mutex()
    {
        SaveOffsets();
        LoadOffsets();
    }

    ~PersistentQueue()
    {
        stream.flush();
    }

    void SaveOffsets()
    {
        stream.seekg(0, std::ios::end);
        if (stream.tellg() < HEADER_SIZE)
        {
            start_position = HEADER_SIZE;
            end_position = UNINITIALIZED;
        }

        //insert_stream.seekp(0, std::ios::beg);
        insert_stream << std::setw(INDEX_SIZE) << start_position;
        insert_stream << std::setw(INDEX_SIZE) << end_position;
        insert_stream.flush();
    }

    void LoadOffsets()
    {
        stream.seekg(0, std::ios::beg);

        std::string buffer;
        stream.read(&buffer[0], INDEX_SIZE);
        boost::trim(buffer);
        start_position = std::stoi(buffer);

        stream.read(&buffer[0], INDEX_SIZE);
        boost::trim(buffer);
        end_position = std::stoi(buffer);
    }

    void Enqueue(T e)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        std::string element_as_string = Serialize<T>(e);

        LoadOffsets();

        stream.seekg(0, std::ios::end);
        end_position = stream.tellg();

        insert_stream.seekp(INDEX_SIZE, std::ios::beg);
        insert_stream << std::setw(INDEX_SIZE) << end_position;
        insert_stream.flush();

        stream.seekp(0, std::ios::end);
        stream << element_as_string;
        stream.flush();
    }

    void Dequeue()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        LoadOffsets();

        for (T element : *this)
        {
            start_position += Serialize<T>(element).length();
            stream.seekp(0, std::ios::beg);
            stream << std::setw(INDEX_SIZE) << start_position;
            break;
        }
    }

    T Last()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        T empty;
        stream.seekg(0, std::ios::end);
        if (stream.tellg() <= HEADER_SIZE)
        {
            return empty;
        }

        LoadOffsets();

        stream.seekg(end_position, std::ios::beg);

        return Deserialize<T>(stream);
    }

private:

    T getElementAt(int64_t index)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        stream.seekg(index, std::ios::beg);
        return Deserialize<T>(stream);
    }

    int64_t getElementSizeAt(int64_t index)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        stream.seekg(index, std::ios::beg);
        return Serialize<T>(Deserialize<T>(stream)).length();
    }

    int64_t getFirstElementIndex()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        LoadOffsets();

        return start_position;
    }

    int64_t getLastElementIndex()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        stream.seekg(0, std::ios::end);
        return stream.tellg();
    }

    std::fstream file;

    std::iostream& stream;

    std::fstream insert_file;

    std::iostream& insert_stream;

    std::streampos start_position;

    std::streampos end_position;

    std::recursive_mutex mutex;

    constexpr static const int64_t INDEX_SIZE = 10;

    constexpr static const int64_t HEADER_SIZE = INDEX_SIZE * 2;

    constexpr static const int64_t UNINITIALIZED = -1;
};

#endif
<commit_msg>Add rollover queue<commit_after>#ifndef __QUEUE_HPP_INCLUDED__
#define __QUEUE_HPP_INCLUDED__

#include <cstdint>
#include <fstream>
#include <mutex>

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

#include "serialization.hpp"

namespace fs = boost::filesystem;

template <typename T>
class BaseQueue
{
private:

    virtual T getElementAt(int64_t index) = 0;

    virtual int64_t getElementSizeAt(int64_t index) = 0;

    virtual int64_t getFirstElementIndex() = 0;

    virtual int64_t getLastElementIndex() = 0;

    class Iterator
    {
    public:

        Iterator(BaseQueue<T> *queue_, int64_t index_)
            : queue(queue_), index(index_)
        {
        }

        T operator*()
        {
            return queue->getElementAt(index);
        }

        Iterator& operator++()
        {
            int64_t size = queue->getElementSizeAt(index);
            index += size;
            return *this;
        }

        bool operator!=(const Iterator& iterator)
        {
            return index != iterator.index;
        }

    private:

        BaseQueue<T> *queue;

        int64_t index;
    };

public:

    virtual void Enqueue(T e) = 0;

    virtual void Dequeue() = 0;

    virtual T Last() = 0;

    Iterator begin()
    {
        return Iterator(this, getFirstElementIndex());
    }

    Iterator end()
    {
        return Iterator(this, getLastElementIndex());
    }
};

template <typename T>
class VolatileQueue : public BaseQueue<T>
{
public:

    void Enqueue(T e)
    {
        data.push_back(e);
    }

    void Dequeue()
    {
        if (!data.empty())
        {
            data.erase(data.begin());
        }
    }

    T Last()
    {
        T empty;
        return data.size() > 0 ? data[data.size() - 1 ] : empty;
    }

private:

    T getElementAt(int64_t index)
    {
        return data[index];
    }

    int64_t getElementSizeAt(int64_t index)
    {
        return 1;
    }

    int64_t getFirstElementIndex()
    {
        return 0;
    }

    int64_t getLastElementIndex()
    {
        return data.size();
    }

    std::vector<T> data;
};

template <typename T>
class PersistentQueue : public BaseQueue<T>
{
public:

    PersistentQueue(std::string filename)
        : PersistentQueue(".", filename)
    {
    }

    PersistentQueue(std::string dirname, std::string filename)
        : file((fs::path(dirname) / fs::path(filename)).string(),
               std::ios::out | std::ios::in | std::ios::app | std::ios::binary),
          stream(file),
          insert_file((fs::path(dirname) / fs::path(filename)).string(),
                       std::ios::in | std::ios::out | std::ios::binary),
          insert_stream(insert_file),
          start_position(0),
          end_position(0),
          mutex()
    {
        SaveOffsets();
        LoadOffsets();
    }

    PersistentQueue(std::iostream& stream)
        : stream(stream),
          insert_stream(stream),
          start_position(0),
          end_position(0),
          mutex()
    {
        SaveOffsets();
        LoadOffsets();
    }

    ~PersistentQueue()
    {
        stream.flush();
    }

    void SaveOffsets()
    {
        stream.seekg(0, std::ios::end);
        if (stream.tellg() < HEADER_SIZE)
        {
            start_position = HEADER_SIZE;
            end_position = UNINITIALIZED;
        }

        //insert_stream.seekp(0, std::ios::beg);
        insert_stream << std::setw(INDEX_SIZE) << start_position;
        insert_stream << std::setw(INDEX_SIZE) << end_position;
        insert_stream.flush();
    }

    void LoadOffsets()
    {
        stream.seekg(0, std::ios::beg);

        std::string buffer;
        stream.read(&buffer[0], INDEX_SIZE);
        boost::trim(buffer);
        start_position = std::stoi(buffer);

        stream.read(&buffer[0], INDEX_SIZE);
        boost::trim(buffer);
        end_position = std::stoi(buffer);
    }

    void Enqueue(T e)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        std::string element_as_string = Serialize<T>(e);

        LoadOffsets();

        stream.seekg(0, std::ios::end);
        end_position = stream.tellg();

        insert_stream.seekp(INDEX_SIZE, std::ios::beg);
        insert_stream << std::setw(INDEX_SIZE) << end_position;
        insert_stream.flush();

        stream.seekp(0, std::ios::end);
        stream << element_as_string;
        stream.flush();
    }

    void Dequeue()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        LoadOffsets();

        for (T element : *this)
        {
            start_position += Serialize<T>(element).length();
            stream.seekp(0, std::ios::beg);
            stream << std::setw(INDEX_SIZE) << start_position;
            break;
        }
    }

    T Last()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        T empty;
        stream.seekg(0, std::ios::end);
        if (stream.tellg() <= HEADER_SIZE)
        {
            return empty;
        }

        LoadOffsets();

        stream.seekg(end_position, std::ios::beg);

        return Deserialize<T>(stream);
    }

private:

    T getElementAt(int64_t index)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        stream.seekg(index, std::ios::beg);
        return Deserialize<T>(stream);
    }

    int64_t getElementSizeAt(int64_t index)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        stream.seekg(index, std::ios::beg);
        return Serialize<T>(Deserialize<T>(stream)).length();
    }

    int64_t getFirstElementIndex()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        LoadOffsets();

        return start_position;
    }

    int64_t getLastElementIndex()
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);

        stream.seekg(0, std::ios::end);
        return stream.tellg();
    }

    std::fstream file;

    std::iostream& stream;

    std::fstream insert_file;

    std::iostream& insert_stream;

    std::streampos start_position;

    std::streampos end_position;

    std::recursive_mutex mutex;

    constexpr static const int64_t INDEX_SIZE = 10;

    constexpr static const int64_t HEADER_SIZE = INDEX_SIZE * 2;

    constexpr static const int64_t UNINITIALIZED = -1;
};

template <typename T>
class RolloverQueue
{
private:

    std::streampos get_start_position()
    {
        stream.seekg(0 * INDEX_SIZE, std::ios::beg);
        std::string buffer;
        stream.read(&buffer[0], INDEX_SIZE);
        boost::trim(buffer);
        return static_cast<std::streampos>(std::stoi(buffer));
    }

    std::streampos get_end_position()
    {
        stream.seekg(1 * INDEX_SIZE, std::ios::beg);
        std::string buffer;
        stream.read(&buffer[0], INDEX_SIZE);
        boost::trim(buffer);
        return static_cast<std::streampos>(std::stoi(buffer));
    }

    std::iostream& stream;

    std::iostream& insert_stream;

    std::streampos rollover_size;

    constexpr static const int64_t INDEX_SIZE = 10;

    constexpr static const int64_t UNINITIALIZED = -1;

    constexpr static const int64_t HEADER_SIZE = INDEX_SIZE * 2;

    class Iterator
    {
    public:

        Iterator(
            std::iostream& stream,
            std::streampos position,
            std::streampos rollover
        )
            : stream(stream),
              position(position),
              rollover(rollover)
        {
        }

        T operator*()
        {
            stream.seekg(position, std::ios::beg);

            return Deserialize<T>(stream);
        }

        Iterator& operator++()
        {
            if (position <= rollover)
            {
                stream.seekg(position, std::ios::beg);
                position += Serialize<T>(Deserialize<T>(stream)).length();
            }
            else
            {
                position = HEADER_SIZE;
            }

            return *this;
        }

        bool operator!=(const Iterator& iterator)
        {
            return position != iterator.position;
        }

    private:

        std::iostream& stream;

        std::streampos position;

        std::streampos rollover;

        constexpr static const int64_t INDEX_SIZE = 10;

        constexpr static const int64_t HEADER_SIZE = INDEX_SIZE * 3;
    };

public:

    RolloverQueue(std::iostream& stream, std::streampos rollover_size=65536)
        : stream(stream),
          insert_stream(stream),
          rollover_size(rollover_size)
    {
        stream.seekg(0, std::ios::end);
        if (stream.tellg() < HEADER_SIZE)
        {
            insert_stream << std::setw(INDEX_SIZE) << HEADER_SIZE;
            insert_stream << std::setw(INDEX_SIZE) << HEADER_SIZE;
        }
    }

    void Enqueue(T e)
    {
        std::string element_as_string = Serialize<T>(e);
        auto size = element_as_string.length();

        std::streampos position = get_end_position();
        if (position + static_cast<std::streampos>(size) < rollover_size)
        {
            // rollover and over-write existing entries
        }
        stream.seekp(position, std::ios::beg);
        stream << element_as_string;
        stream.flush();
    }

    void Dequeue()
    {
        auto position = get_start_position();
        stream.seekg(position, std::ios::beg);

        auto next = position + Serialize<T>(Deserialize<T>(stream)).length();

        insert_stream << std::setw(INDEX_SIZE) << next;
        // TODO: close and reset insert_stream?
    }

    T Last()
    {
        return *end();
    }

    Iterator begin()
    {
        return Iterator(stream, get_start_position(), rollover_size);
    }

    Iterator end()
    {
        return Iterator(stream, get_end_position(), rollover_size);
    }
};

#endif
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/except.hxx
 *
 *   DESCRIPTION
 *      definition of libpqxx exception classes
 *   pqxx::sql_error, pqxx::broken_connection, pqxx::in_doubt_error, ...
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/except instead.
 *
 * Copyright (c) 2003-2007, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

#include <stdexcept>

#include "pqxx/util"

namespace pqxx
{

/**
 * @addtogroup exception Exception classes
 *
 * These exception classes follow, roughly, the two-level hierarchy defined by
 * the PostgreSQL error codes (see Appendix A of the PostgreSQL documentation
 * corresponding to your server version).  The hierarchy given here is, as yet,
 * not a complete mirror of the error codes.  There are some other differences
 * as well, e.g. the error code statement_completion_unknown has a separate
 * status in libpqxx as in_doubt_error, and too_many_connections is classified
 * as a broken_connection rather than a subtype of insufficient_resources.
 *
 * @see http://www.postgresql.org/docs/8.1/interactive/errcodes-appendix.html
 *
 * @{
 */

/// Mixin base class to identify libpqxx-specific exception types
/**
 * If you wish to catch all exception types specific to libpqxx for some reason,
 * catch this type.  All of libpqxx's exception classes are derived from it
 * through multiple-inheritance (they also fit into the standard library's
 * exception hierarchy in more fitting places).
 *
 * This class is not derived from std::exception, since that could easily lead
 * to exception classes with multiple std::exception base-class objects.  As
 * Bart Samwel points out, "catch" is subject to some nasty fineprint in such
 * cases.
 */
class PQXX_LIBEXPORT pqxx_exception
{
public:
  /// Support run-time polymorphism, and keep this class abstract
  virtual ~pqxx_exception() throw () =0;

  /// Return std::exception base-class object
  /** Use this to get at the exception's what() function, or to downcast to a
   * more specific type using dynamic_cast.
   *
   * Casting directly from pqxx_exception to a specific exception type is not
   * likely to work since pqxx_exception is not (and could not safely be)
   * derived from std::exception.
   *
   * For example, to test dynamically whether an exception is an sql_error:
   *
   * @code
   * try
   * {
   *   // ...
   * }
   * catch (const pqxx::pqxx_exception &e)
   * {
   *   std::cerr << e.base().what() << std::endl;
   *   const pqxx::sql_error *s=dynamic_cast<const pqxx::sql_error*>(&e.base());
   *   if (s) std::cerr << "Query was: " << s->query() << std::endl;
   * }
   * @endcode
   */
  virtual const PGSTD::exception &base() const throw () =0;		//[t0]
};

/// Exception class for lost or failed backend connection.
/**
 * @warning When this happens on Unix-like systems, you may also get a SIGPIPE
 * signal.  That signal aborts the program by default, so if you wish to be able
 * to continue after a connection breaks, be sure to disarm this signal.
 *
 * If you're working on a Unix-like system, see the manual page for
 * @c signal (2) on how to deal with SIGPIPE.  The easiest way to make this
 * signal harmless is to make your program ignore it:
 *
 * @code
 * #include <signal.h>
 *
 * int main()
 * {
 *   signal(SIGPIPE, SIG_IGN);
 *   // ...
 * @endcode
 */
class PQXX_LIBEXPORT broken_connection :
  public pqxx_exception, public PGSTD::runtime_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
public:
  broken_connection();
  explicit broken_connection(const PGSTD::string &);
};

/// Exception class for failed queries.
/** Carries a copy of the failed query in addition to a regular error message */
class PQXX_LIBEXPORT sql_error :
  public pqxx_exception, public PGSTD::runtime_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
  PGSTD::string m_Q;

public:
  sql_error();
  explicit sql_error(const PGSTD::string &);
  sql_error(const PGSTD::string &, const PGSTD::string &Q);
  virtual ~sql_error() throw ();

  /// The query whose execution triggered the exception
  const PGSTD::string &query() const throw ();				//[t56]
};

// TODO: should this be called statement_completion_unknown!?
/// "Help, I don't know whether transaction was committed successfully!"
/** Exception that might be thrown in rare cases where the connection to the
 * database is lost while finishing a database transaction, and there's no way
 * of telling whether it was actually executed by the backend.  In this case
 * the database is left in an indeterminate (but consistent) state, and only
 * manual inspection will tell which is the case.
 */
class PQXX_LIBEXPORT in_doubt_error :
  public pqxx_exception, public PGSTD::runtime_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
public:
  explicit in_doubt_error(const PGSTD::string &);
};

/// Internal error in libpqxx library
class PQXX_LIBEXPORT internal_error :
  public pqxx_exception, public PGSTD::logic_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
public:
  explicit internal_error(const PGSTD::string &);
};

/// Database feature not supported in current setup
class PQXX_LIBEXPORT feature_not_supported : public sql_error
{
public:
  explicit feature_not_supported(const PGSTD::string &err) : sql_error(err) {}
  feature_not_supported(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

/// Error in data provided to SQL statement
class PQXX_LIBEXPORT data_exception : public sql_error
{
public:
  explicit data_exception(const PGSTD::string &err) : sql_error(err) {}
  data_exception(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT integrity_constraint_violation : public sql_error
{
public:
  explicit integrity_constraint_violation(const PGSTD::string &err) :
	sql_error(err) {}
  integrity_constraint_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	sql_error(err, Q) {}
};

class PQXX_LIBEXPORT restrict_violation :
  public integrity_constraint_violation
{
  explicit restrict_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT not_null_violation :
  public integrity_constraint_violation
{
  explicit not_null_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT foreign_key_violation :
  public integrity_constraint_violation
{
  explicit foreign_key_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT unique_violation :
  public integrity_constraint_violation
{
  explicit unique_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT check_violation :
  public integrity_constraint_violation
{
  explicit check_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT invalid_cursor_state : public sql_error
{
public:
  explicit invalid_cursor_state(const PGSTD::string &err) : sql_error(err) {}
  invalid_cursor_state(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT invalid_sql_statement_name : public sql_error
{
public:
  explicit invalid_sql_statement_name(const PGSTD::string &err) :
	sql_error(err) {}
  invalid_sql_statement_name(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT invalid_cursor_name : public sql_error
{
public:
  explicit invalid_cursor_name(const PGSTD::string &err) : sql_error(err) {}
  invalid_cursor_name(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT syntax_error : public sql_error
{
public:
  explicit syntax_error(const PGSTD::string &err) : sql_error(err) {}
  syntax_error(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT undefined_column : public syntax_error
{
public:
  explicit undefined_column(const PGSTD::string &err) : syntax_error(err) {}
  undefined_column(const PGSTD::string &err, const PGSTD::string &Q) :
    syntax_error(err, Q) {}
};

class PQXX_LIBEXPORT undefined_function : public syntax_error
{
public:
  explicit undefined_function(const PGSTD::string &err) : syntax_error(err) {}
  undefined_function(const PGSTD::string &err, const PGSTD::string &Q) :
    syntax_error(err, Q) {}
};

class PQXX_LIBEXPORT undefined_table : public syntax_error
{
public:
  explicit undefined_table(const PGSTD::string &err) : syntax_error(err) {}
  undefined_table(const PGSTD::string &err, const PGSTD::string &Q) :
    syntax_error(err, Q) {}
};

class PQXX_LIBEXPORT insufficient_privilege : public sql_error
{
public:
  explicit insufficient_privilege(const PGSTD::string &err) : sql_error(err) {}
  insufficient_privilege(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

/// Resource shortage on the server
class PQXX_LIBEXPORT insufficient_resources : public sql_error
{
public:
  explicit insufficient_resources(const PGSTD::string &err) : sql_error(err) {}
  insufficient_resources(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT disk_full : public insufficient_resources
{
public:
  explicit disk_full(const PGSTD::string &err) : insufficient_resources(err) {}
  disk_full(const PGSTD::string &err, const PGSTD::string &Q) :
	insufficient_resources(err,Q) {}
};

class PQXX_LIBEXPORT out_of_memory : public insufficient_resources
{
public:
  explicit out_of_memory(const PGSTD::string &err) :
	insufficient_resources(err) {}
  out_of_memory(const PGSTD::string &err, const PGSTD::string &Q) :
	insufficient_resources(err,Q) {}
};

class PQXX_LIBEXPORT too_many_connections : public broken_connection
{
public:
  explicit too_many_connections(const PGSTD::string &err) :
	broken_connection(err) {}
};

/**
 * @}
 */

}

#include "pqxx/compiler-internal-post.hxx"
<commit_msg>Corrected constructors.<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/except.hxx
 *
 *   DESCRIPTION
 *      definition of libpqxx exception classes
 *   pqxx::sql_error, pqxx::broken_connection, pqxx::in_doubt_error, ...
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/except instead.
 *
 * Copyright (c) 2003-2007, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

#include <stdexcept>

#include "pqxx/util"

namespace pqxx
{

/**
 * @addtogroup exception Exception classes
 *
 * These exception classes follow, roughly, the two-level hierarchy defined by
 * the PostgreSQL error codes (see Appendix A of the PostgreSQL documentation
 * corresponding to your server version).  The hierarchy given here is, as yet,
 * not a complete mirror of the error codes.  There are some other differences
 * as well, e.g. the error code statement_completion_unknown has a separate
 * status in libpqxx as in_doubt_error, and too_many_connections is classified
 * as a broken_connection rather than a subtype of insufficient_resources.
 *
 * @see http://www.postgresql.org/docs/8.1/interactive/errcodes-appendix.html
 *
 * @{
 */

/// Mixin base class to identify libpqxx-specific exception types
/**
 * If you wish to catch all exception types specific to libpqxx for some reason,
 * catch this type.  All of libpqxx's exception classes are derived from it
 * through multiple-inheritance (they also fit into the standard library's
 * exception hierarchy in more fitting places).
 *
 * This class is not derived from std::exception, since that could easily lead
 * to exception classes with multiple std::exception base-class objects.  As
 * Bart Samwel points out, "catch" is subject to some nasty fineprint in such
 * cases.
 */
class PQXX_LIBEXPORT pqxx_exception
{
public:
  /// Support run-time polymorphism, and keep this class abstract
  virtual ~pqxx_exception() throw () =0;

  /// Return std::exception base-class object
  /** Use this to get at the exception's what() function, or to downcast to a
   * more specific type using dynamic_cast.
   *
   * Casting directly from pqxx_exception to a specific exception type is not
   * likely to work since pqxx_exception is not (and could not safely be)
   * derived from std::exception.
   *
   * For example, to test dynamically whether an exception is an sql_error:
   *
   * @code
   * try
   * {
   *   // ...
   * }
   * catch (const pqxx::pqxx_exception &e)
   * {
   *   std::cerr << e.base().what() << std::endl;
   *   const pqxx::sql_error *s=dynamic_cast<const pqxx::sql_error*>(&e.base());
   *   if (s) std::cerr << "Query was: " << s->query() << std::endl;
   * }
   * @endcode
   */
  virtual const PGSTD::exception &base() const throw () =0;		//[t0]
};

/// Exception class for lost or failed backend connection.
/**
 * @warning When this happens on Unix-like systems, you may also get a SIGPIPE
 * signal.  That signal aborts the program by default, so if you wish to be able
 * to continue after a connection breaks, be sure to disarm this signal.
 *
 * If you're working on a Unix-like system, see the manual page for
 * @c signal (2) on how to deal with SIGPIPE.  The easiest way to make this
 * signal harmless is to make your program ignore it:
 *
 * @code
 * #include <signal.h>
 *
 * int main()
 * {
 *   signal(SIGPIPE, SIG_IGN);
 *   // ...
 * @endcode
 */
class PQXX_LIBEXPORT broken_connection :
  public pqxx_exception, public PGSTD::runtime_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
public:
  broken_connection();
  explicit broken_connection(const PGSTD::string &);
};

/// Exception class for failed queries.
/** Carries a copy of the failed query in addition to a regular error message */
class PQXX_LIBEXPORT sql_error :
  public pqxx_exception, public PGSTD::runtime_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
  PGSTD::string m_Q;

public:
  sql_error();
  explicit sql_error(const PGSTD::string &);
  sql_error(const PGSTD::string &, const PGSTD::string &Q);
  virtual ~sql_error() throw ();

  /// The query whose execution triggered the exception
  const PGSTD::string &query() const throw ();				//[t56]
};

// TODO: should this be called statement_completion_unknown!?
/// "Help, I don't know whether transaction was committed successfully!"
/** Exception that might be thrown in rare cases where the connection to the
 * database is lost while finishing a database transaction, and there's no way
 * of telling whether it was actually executed by the backend.  In this case
 * the database is left in an indeterminate (but consistent) state, and only
 * manual inspection will tell which is the case.
 */
class PQXX_LIBEXPORT in_doubt_error :
  public pqxx_exception, public PGSTD::runtime_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
public:
  explicit in_doubt_error(const PGSTD::string &);
};

/// Internal error in libpqxx library
class PQXX_LIBEXPORT internal_error :
  public pqxx_exception, public PGSTD::logic_error
{
  virtual const PGSTD::exception &base() const throw () { return *this; }
public:
  explicit internal_error(const PGSTD::string &);
};

/// Database feature not supported in current setup
class PQXX_LIBEXPORT feature_not_supported : public sql_error
{
public:
  explicit feature_not_supported(const PGSTD::string &err) : sql_error(err) {}
  feature_not_supported(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

/// Error in data provided to SQL statement
class PQXX_LIBEXPORT data_exception : public sql_error
{
public:
  explicit data_exception(const PGSTD::string &err) : sql_error(err) {}
  data_exception(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT integrity_constraint_violation : public sql_error
{
public:
  explicit integrity_constraint_violation(const PGSTD::string &err) :
	sql_error(err) {}
  integrity_constraint_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	sql_error(err, Q) {}
};

class PQXX_LIBEXPORT restrict_violation :
  public integrity_constraint_violation
{
public:
  explicit restrict_violation(const PGSTD::string &err) :
	integrity_constraint_violation(err) {}
  restrict_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT not_null_violation :
  public integrity_constraint_violation
{
public:
  explicit not_null_violation(const PGSTD::string &err) :
	integrity_constraint_violation(err) {}
  not_null_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT foreign_key_violation :
  public integrity_constraint_violation
{
public:
  explicit foreign_key_violation(const PGSTD::string &err) :
	integrity_constraint_violation(err) {}
  foreign_key_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT unique_violation :
  public integrity_constraint_violation
{
public:
  explicit unique_violation(const PGSTD::string &err) :
	integrity_constraint_violation(err) {}
  unique_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT check_violation :
  public integrity_constraint_violation
{
public:
  explicit check_violation(const PGSTD::string &err) :
	integrity_constraint_violation(err) {}
  check_violation(const PGSTD::string &err,
	const PGSTD::string &Q) :
	integrity_constraint_violation(err, Q) {}
};

class PQXX_LIBEXPORT invalid_cursor_state : public sql_error
{
public:
  explicit invalid_cursor_state(const PGSTD::string &err) : sql_error(err) {}
  invalid_cursor_state(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT invalid_sql_statement_name : public sql_error
{
public:
  explicit invalid_sql_statement_name(const PGSTD::string &err) :
	sql_error(err) {}
  invalid_sql_statement_name(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT invalid_cursor_name : public sql_error
{
public:
  explicit invalid_cursor_name(const PGSTD::string &err) : sql_error(err) {}
  invalid_cursor_name(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT syntax_error : public sql_error
{
public:
  explicit syntax_error(const PGSTD::string &err) : sql_error(err) {}
  syntax_error(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT undefined_column : public syntax_error
{
public:
  explicit undefined_column(const PGSTD::string &err) : syntax_error(err) {}
  undefined_column(const PGSTD::string &err, const PGSTD::string &Q) :
    syntax_error(err, Q) {}
};

class PQXX_LIBEXPORT undefined_function : public syntax_error
{
public:
  explicit undefined_function(const PGSTD::string &err) : syntax_error(err) {}
  undefined_function(const PGSTD::string &err, const PGSTD::string &Q) :
    syntax_error(err, Q) {}
};

class PQXX_LIBEXPORT undefined_table : public syntax_error
{
public:
  explicit undefined_table(const PGSTD::string &err) : syntax_error(err) {}
  undefined_table(const PGSTD::string &err, const PGSTD::string &Q) :
    syntax_error(err, Q) {}
};

class PQXX_LIBEXPORT insufficient_privilege : public sql_error
{
public:
  explicit insufficient_privilege(const PGSTD::string &err) : sql_error(err) {}
  insufficient_privilege(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

/// Resource shortage on the server
class PQXX_LIBEXPORT insufficient_resources : public sql_error
{
public:
  explicit insufficient_resources(const PGSTD::string &err) : sql_error(err) {}
  insufficient_resources(const PGSTD::string &err, const PGSTD::string &Q) :
	sql_error(err,Q) {}
};

class PQXX_LIBEXPORT disk_full : public insufficient_resources
{
public:
  explicit disk_full(const PGSTD::string &err) : insufficient_resources(err) {}
  disk_full(const PGSTD::string &err, const PGSTD::string &Q) :
	insufficient_resources(err,Q) {}
};

class PQXX_LIBEXPORT out_of_memory : public insufficient_resources
{
public:
  explicit out_of_memory(const PGSTD::string &err) :
	insufficient_resources(err) {}
  out_of_memory(const PGSTD::string &err, const PGSTD::string &Q) :
	insufficient_resources(err,Q) {}
};

class PQXX_LIBEXPORT too_many_connections : public broken_connection
{
public:
  explicit too_many_connections(const PGSTD::string &err) :
	broken_connection(err) {}
};

/**
 * @}
 */

}

#include "pqxx/compiler-internal-post.hxx"
<|endoftext|>


<commit_before>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <deque>
#include <cassert>
#include <functional>
#include <iostream>
#include <iterator>

#include <boost/array.hpp>
#include <boost/container/set.hpp>
#include <boost/container/node_allocator.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

namespace rank_filter
{

template<class I1,
         class I2>
inline void lineRankOrderFilter1D(const I1& src_begin, const I1& src_end,
        I2& dest_begin, I2& dest_end,
        size_t half_length, double rank)
{
    // Types in use.
    typedef typename std::iterator_traits<I1>::value_type T1;
    typedef typename std::iterator_traits<I2>::value_type T2;
    typedef typename std::iterator_traits<I1>::difference_type I1_diff_t;
    typedef typename std::iterator_traits<I2>::difference_type I2_diff_t;

    // Establish common types to work with source and destination values.
    BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
    typedef T1 T;
    typedef typename boost::common_type<I1_diff_t, I2_diff_t>::type I_diff_t;

    // Define container types that will be used.
    typedef boost::container::multiset< T,
            std::less<T>,
            boost::container::node_allocator<T>,
            boost::container::tree_assoc_options< boost::container::tree_type<boost::container::scapegoat_tree> >::type> multiset;
    typedef std::deque< typename multiset::iterator > deque;

    // The position of the window.
    I_diff_t window_begin = 0;

    // Lengths.
    const I_diff_t src_size = std::distance(src_begin, src_end);
    const I_diff_t dest_size = std::distance(dest_begin, dest_end);

    // Ensure the result will fit.
    assert(src_size <= dest_size);

    // Window length cannot exceed input data with reflection.
    assert((half_length + 1) <= src_size);

    // Rank must be in the range 0 to 1.
    assert((0 <= rank) && (rank <= 1));

    // Find window offset corresponding to this rank.
    const I_diff_t rank_pos = static_cast<I_diff_t>(boost::math::round(rank * (2 * half_length)));

    multiset sorted_window;
    deque window_iters(2 * half_length + 1);

    // Get the initial sorted window.
    // Include the reflection.
    for (I_diff_t j = 0; j < half_length; j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + half_length - j]);
    }
    for (I_diff_t j = half_length; j < (2 * half_length + 1); j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + j - half_length]);
    }

    typename multiset::iterator rank_point = sorted_window.begin();

    for (I_diff_t i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    typename multiset::iterator prev_iter;
    T prev_value;
    T next_value;
    while ( window_begin < src_size )
    {
        dest_begin[window_begin] = *rank_point;

        prev_iter = window_iters.front();
        prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        if ( window_begin == src_size )
        {
            next_value = prev_value;
        }
        else if ( window_begin < (src_size - half_length) )
        {
            next_value = src_begin[window_begin + half_length];
        }
        else
        {
            next_value = *(window_iters[(2 * (src_size - (window_begin + 1)))]);
        }

        if ( ( *rank_point < prev_value ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < prev_value ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

}

namespace std
{
    template <class T, size_t N>
    ostream& operator<<(ostream& out, const boost::array<T, N>& that)
    {
        out << "{ ";
        for (unsigned int i = 0; i < (N - 1); i++)
        {
            out << that[i] << ", ";
        }
        out << that[N - 1] << " }";

        return(out);
    }
}

#endif //__RANK_FILTER__
<commit_msg>Move `window_begin` definition next to others<commit_after>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <deque>
#include <cassert>
#include <functional>
#include <iostream>
#include <iterator>

#include <boost/array.hpp>
#include <boost/container/set.hpp>
#include <boost/container/node_allocator.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

namespace rank_filter
{

template<class I1,
         class I2>
inline void lineRankOrderFilter1D(const I1& src_begin, const I1& src_end,
        I2& dest_begin, I2& dest_end,
        size_t half_length, double rank)
{
    // Types in use.
    typedef typename std::iterator_traits<I1>::value_type T1;
    typedef typename std::iterator_traits<I2>::value_type T2;
    typedef typename std::iterator_traits<I1>::difference_type I1_diff_t;
    typedef typename std::iterator_traits<I2>::difference_type I2_diff_t;

    // Establish common types to work with source and destination values.
    BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
    typedef T1 T;
    typedef typename boost::common_type<I1_diff_t, I2_diff_t>::type I_diff_t;

    // Define container types that will be used.
    typedef boost::container::multiset< T,
            std::less<T>,
            boost::container::node_allocator<T>,
            boost::container::tree_assoc_options< boost::container::tree_type<boost::container::scapegoat_tree> >::type> multiset;
    typedef std::deque< typename multiset::iterator > deque;

    // Lengths.
    const I_diff_t src_size = std::distance(src_begin, src_end);
    const I_diff_t dest_size = std::distance(dest_begin, dest_end);

    // Ensure the result will fit.
    assert(src_size <= dest_size);

    // Window length cannot exceed input data with reflection.
    assert((half_length + 1) <= src_size);

    // Rank must be in the range 0 to 1.
    assert((0 <= rank) && (rank <= 1));

    // The position of the window.
    I_diff_t window_begin = 0;

    // Find window offset corresponding to this rank.
    const I_diff_t rank_pos = static_cast<I_diff_t>(boost::math::round(rank * (2 * half_length)));

    multiset sorted_window;
    deque window_iters(2 * half_length + 1);

    // Get the initial sorted window.
    // Include the reflection.
    for (I_diff_t j = 0; j < half_length; j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + half_length - j]);
    }
    for (I_diff_t j = half_length; j < (2 * half_length + 1); j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + j - half_length]);
    }

    typename multiset::iterator rank_point = sorted_window.begin();

    for (I_diff_t i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    typename multiset::iterator prev_iter;
    T prev_value;
    T next_value;
    while ( window_begin < src_size )
    {
        dest_begin[window_begin] = *rank_point;

        prev_iter = window_iters.front();
        prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        if ( window_begin == src_size )
        {
            next_value = prev_value;
        }
        else if ( window_begin < (src_size - half_length) )
        {
            next_value = src_begin[window_begin + half_length];
        }
        else
        {
            next_value = *(window_iters[(2 * (src_size - (window_begin + 1)))]);
        }

        if ( ( *rank_point < prev_value ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < prev_value ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

}

namespace std
{
    template <class T, size_t N>
    ostream& operator<<(ostream& out, const boost::array<T, N>& that)
    {
        out << "{ ";
        for (unsigned int i = 0; i < (N - 1); i++)
        {
            out << that[i] << ", ";
        }
        out << that[N - 1] << " }";

        return(out);
    }
}

#endif //__RANK_FILTER__
<|endoftext|>


<commit_before><commit_msg>error: class 'SotStorage' is implicitly friends with itself<commit_after><|endoftext|>


<commit_before>/* Socket
 * Copyright (c) 2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "SocketAddress.h"
#include "NetworkStack.h"
#include <string.h>
#include "mbed.h"

static bool ipv4_is_valid(const char *addr)
{
    int i = 0;

    // Check each digit for [0-9.]
    for (; addr[i]; i++) {
        if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') {
            return false;
        }
    }

    // Ending with '.' garuntees host
    if (i > 0 && addr[i-1] == '.') {
        return false;
    }

    return true;
}

static bool ipv6_is_valid(const char *addr)
{
    // Check each digit for [0-9a-fA-F:]
    for (int i = 0; addr[i]; i++) {
        if (!(addr[i] >= '0' && addr[i] <= '9') &&
            !(addr[i] >= 'a' && addr[i] <= 'f') &&
            !(addr[i] >= 'A' && addr[i] <= 'F') &&
            addr[i] != ':') {
            return false;
        }
    }

    return true;
}

static void ipv4_from_address(uint8_t *bytes, const char *addr)
{
    sscanf(addr, "%hhu.%hhu.%hhu.%hhu", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);
}

static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
    int count = 0;
    int i = 0;

    for (; count < NSAPI_IPv6_BYTES/2; count++) {
        int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
        if (scanned < 1) {
            return count;
        }

        for (; chunk[i] != ':'; i++) {
            if (!chunk[i]) {
                return count+1;
            }
        }

        i++;
    }

    return count;
}

static void ipv6_from_address(uint8_t *bytes, const char *addr)
{
    // Start with zeroed address
    uint16_t shorts[NSAPI_IPv6_BYTES/2];
    memset(shorts, 0, sizeof shorts);

    int suffix = 0;

    // Find double colons and scan suffix
    for (int i = 0; addr[i]; i++) {
        if (addr[i] == ':' && addr[i+1] == ':') {
            suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
            break;
        }
    }

    // Move suffix to end
    memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
            suffix*sizeof(uint16_t));

    // Scan prefix
    ipv6_scan_chunk(shorts, &addr[0]);

    // Flip bytes
    for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
        bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
        bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
    }
}

static void ipv4_to_address(char *addr, const uint8_t *bytes)
{
    sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
}

static void ipv6_to_address(char *addr, const uint8_t *bytes)
{
    for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
        sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
        addr[5*i+4] = ':';
    }
    addr[NSAPI_IPv6_SIZE-1] = '\0';
}

SocketAddress::SocketAddress(NetworkStack *iface, const char *host, uint16_t port)
{
    // Check for valid IP addresses
    if (host && ipv4_is_valid(host)) {
        _ip_version = NSAPI_IPv4;
        ipv4_from_address(_ip_bytes, host);
    } else if (host && ipv6_is_valid(host)) {
        _ip_version = NSAPI_IPv6;
        ipv4_from_address(_ip_bytes, host);
    } else {
        // DNS lookup
        int err = iface->gethostbyname(this, host);
        if (!err) {
            set_port(port);
        } else {
            _ip_version = NSAPI_IPv4;
            memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
            set_port(0);
        }
    }
}

SocketAddress::SocketAddress(const char *addr, uint16_t port)
{
    set_ip_address(addr);
    set_port(port);
}

SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
{
    set_ip_bytes(bytes, version);
    set_port(port);
}

SocketAddress::SocketAddress(const SocketAddress &addr)
{
    set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version());
    set_port(addr.get_port());
}

void SocketAddress::set_ip_address(const char *addr)
{
    _ip_address[0] = '\0';

    if (addr && ipv4_is_valid(addr)) {
        _ip_version = NSAPI_IPv4;
        ipv4_from_address(_ip_bytes, addr);
    } else if (addr && ipv6_is_valid(addr)) {
        _ip_version = NSAPI_IPv6;
        ipv6_from_address(_ip_bytes, addr);
    } else {
        _ip_version = NSAPI_IPv4;
        memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
    }
}

void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
{
    _ip_address[0] = '\0';

    if (_ip_version == NSAPI_IPv4) {
        _ip_version = NSAPI_IPv4;
        memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES);
    } else if (_ip_version == NSAPI_IPv6) {
        _ip_version = NSAPI_IPv6;
        memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES);
    } else {
        _ip_version = NSAPI_IPv4;
        memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
    }
}

void SocketAddress::set_port(uint16_t port)
{
    _port = port;
}

const char *SocketAddress::get_ip_address() const
{
    char *ip_address = (char *)_ip_address;

    if (!ip_address[0]) {
        if (_ip_version == NSAPI_IPv4) {
            ipv4_to_address(ip_address, _ip_bytes);
        } else if (_ip_version == NSAPI_IPv6) {
            ipv6_to_address(ip_address, _ip_bytes);
        }
    }

    return ip_address;
}

const void *SocketAddress::get_ip_bytes() const
{
    return _ip_bytes;
}

nsapi_version_t SocketAddress::get_ip_version() const
{
    return _ip_version;
}

uint16_t SocketAddress::get_port() const
{
    return _port;
}

SocketAddress::operator bool() const
{
    int count = 0;
    if (_ip_version == NSAPI_IPv4) {
        count = NSAPI_IPv4_BYTES;
    } else if (_ip_version == NSAPI_IPv6) {
        count = NSAPI_IPv6_BYTES;
    }

    for (int i = 0; i < count; i++) {
        if (_ip_bytes[i]) {
            return true;
        }
    }

    return false;
}
<commit_msg>Added workaround for bug in newlib sscanf<commit_after>/* Socket
 * Copyright (c) 2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "SocketAddress.h"
#include "NetworkStack.h"
#include <string.h>
#include "mbed.h"

static bool ipv4_is_valid(const char *addr)
{
    int i = 0;

    // Check each digit for [0-9.]
    for (; addr[i]; i++) {
        if (!(addr[i] >= '0' && addr[i] <= '9') && addr[i] != '.') {
            return false;
        }
    }

    // Ending with '.' garuntees host
    if (i > 0 && addr[i-1] == '.') {
        return false;
    }

    return true;
}

static bool ipv6_is_valid(const char *addr)
{
    // Check each digit for [0-9a-fA-F:]
    for (int i = 0; addr[i]; i++) {
        if (!(addr[i] >= '0' && addr[i] <= '9') &&
            !(addr[i] >= 'a' && addr[i] <= 'f') &&
            !(addr[i] >= 'A' && addr[i] <= 'F') &&
            addr[i] != ':') {
            return false;
        }
    }

    return true;
}

static void ipv4_from_address(uint8_t *bytes, const char *addr)
{
    int count = 0;
    int i = 0;

    for (; count < NSAPI_IPv4_BYTES; count++) {
        int scanned = sscanf(&addr[i], "%hhu", &bytes[count]);
        if (scanned < 1) {
            return;
        }

        for (; addr[i] != '.'; i++) {
            if (!addr[i]) {
                return;
            }
        }

        i++;
    }
}

static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) {
    int count = 0;
    int i = 0;

    for (; count < NSAPI_IPv6_BYTES/2; count++) {
        int scanned = sscanf(&chunk[i], "%hx", &shorts[count]);
        if (scanned < 1) {
            return count;
        }

        for (; chunk[i] != ':'; i++) {
            if (!chunk[i]) {
                return count+1;
            }
        }

        i++;
    }

    return count;
}

static void ipv6_from_address(uint8_t *bytes, const char *addr)
{
    // Start with zeroed address
    uint16_t shorts[NSAPI_IPv6_BYTES/2];
    memset(shorts, 0, sizeof shorts);

    int suffix = 0;

    // Find double colons and scan suffix
    for (int i = 0; addr[i]; i++) {
        if (addr[i] == ':' && addr[i+1] == ':') {
            suffix = ipv6_scan_chunk(shorts, &addr[i+2]);
            break;
        }
    }

    // Move suffix to end
    memmove(&shorts[NSAPI_IPv6_BYTES/2-suffix], &shorts[0],
            suffix*sizeof(uint16_t));

    // Scan prefix
    ipv6_scan_chunk(shorts, &addr[0]);

    // Flip bytes
    for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
        bytes[2*i+0] = (uint8_t)(shorts[i] >> 8);
        bytes[2*i+1] = (uint8_t)(shorts[i] >> 0);
    }
}

static void ipv4_to_address(char *addr, const uint8_t *bytes)
{
    sprintf(addr, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
}

static void ipv6_to_address(char *addr, const uint8_t *bytes)
{
    for (int i = 0; i < NSAPI_IPv6_BYTES/2; i++) {
        sprintf(&addr[5*i], "%02x%02x", bytes[2*i], bytes[2*i+1]);
        addr[5*i+4] = ':';
    }
    addr[NSAPI_IPv6_SIZE-1] = '\0';
}

SocketAddress::SocketAddress(NetworkStack *iface, const char *host, uint16_t port)
{
    // Check for valid IP addresses
    if (host && ipv4_is_valid(host)) {
        _ip_version = NSAPI_IPv4;
        ipv4_from_address(_ip_bytes, host);
    } else if (host && ipv6_is_valid(host)) {
        _ip_version = NSAPI_IPv6;
        ipv4_from_address(_ip_bytes, host);
    } else {
        // DNS lookup
        int err = iface->gethostbyname(this, host);
        if (!err) {
            set_port(port);
        } else {
            _ip_version = NSAPI_IPv4;
            memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
            set_port(0);
        }
    }
}

SocketAddress::SocketAddress(const char *addr, uint16_t port)
{
    set_ip_address(addr);
    set_port(port);
}

SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port)
{
    set_ip_bytes(bytes, version);
    set_port(port);
}

SocketAddress::SocketAddress(const SocketAddress &addr)
{
    set_ip_bytes(addr.get_ip_bytes(), addr.get_ip_version());
    set_port(addr.get_port());
}

void SocketAddress::set_ip_address(const char *addr)
{
    _ip_address[0] = '\0';

    if (addr && ipv4_is_valid(addr)) {
        _ip_version = NSAPI_IPv4;
        ipv4_from_address(_ip_bytes, addr);
    } else if (addr && ipv6_is_valid(addr)) {
        _ip_version = NSAPI_IPv6;
        ipv6_from_address(_ip_bytes, addr);
    } else {
        _ip_version = NSAPI_IPv4;
        memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
    }
}

void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version)
{
    _ip_address[0] = '\0';

    if (_ip_version == NSAPI_IPv4) {
        _ip_version = NSAPI_IPv4;
        memcpy(_ip_bytes, bytes, NSAPI_IPv4_BYTES);
    } else if (_ip_version == NSAPI_IPv6) {
        _ip_version = NSAPI_IPv6;
        memcpy(_ip_bytes, bytes, NSAPI_IPv6_BYTES);
    } else {
        _ip_version = NSAPI_IPv4;
        memset(_ip_bytes, 0, NSAPI_IPv4_BYTES);
    }
}

void SocketAddress::set_port(uint16_t port)
{
    _port = port;
}

const char *SocketAddress::get_ip_address() const
{
    char *ip_address = (char *)_ip_address;

    if (!ip_address[0]) {
        if (_ip_version == NSAPI_IPv4) {
            ipv4_to_address(ip_address, _ip_bytes);
        } else if (_ip_version == NSAPI_IPv6) {
            ipv6_to_address(ip_address, _ip_bytes);
        }
    }

    return ip_address;
}

const void *SocketAddress::get_ip_bytes() const
{
    return _ip_bytes;
}

nsapi_version_t SocketAddress::get_ip_version() const
{
    return _ip_version;
}

uint16_t SocketAddress::get_port() const
{
    return _port;
}

SocketAddress::operator bool() const
{
    int count = 0;
    if (_ip_version == NSAPI_IPv4) {
        count = NSAPI_IPv4_BYTES;
    } else if (_ip_version == NSAPI_IPv6) {
        count = NSAPI_IPv6_BYTES;
    }

    for (int i = 0; i < count; i++) {
        if (_ip_bytes[i]) {
            return true;
        }
    }

    return false;
}
<|endoftext|>