/*
 * SPDX-FileCopyrightText: 2014 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#ifndef TANGO_CLIENT_DEVICEPIPEBLOB_H
#define TANGO_CLIENT_DEVICEPIPEBLOB_H

#include <tango/client/DataElement.h>
#include <tango/common/tango_const.h>
#include <tango/idl/tango.h>

#include <bitset>
#include <memory>

namespace Tango
{

/**
 * A device pipe blob
 *
 * A device pipe blob. A blob is used to pack data to be sent through device pipe
 *
 *
 * @headerfile tango.h
 * @ingroup Client
 */

class DevicePipeBlob
{
  public:
    ///@privatesection

    enum except_flags
    {
        isempty_flag,
        wrongtype_flag,
        notenoughde_flag,
        blobdenamenotset_flag,
        mixing_flag,
        numFlags
    };

    ///@publicsection
    /**@name Constructors */
    //@{
    /**
     * Create a DevicePipeBlob object.
     *
     * Default constructor.
     *
     */
    DevicePipeBlob();
    /**
     * Create a DevicePipeBlob object with name
     *
     * Create one instance of the DevicePipeBlob class and set its name
     *
     * @param [in] blob_name The blob name
     */
    DevicePipeBlob(const std::string &blob_name);

    //@}

    /**@name Get/Set methods */
    //@{
    /**
     * Set blob name
     *
     * Set the blob name
     *
     * @param [in] blob_name The blob name
     */
    void set_name(const std::string &blob_name)
    {
        name = blob_name;
    }

    /**
     * Get blob name
     *
     * Get the blob name
     *
     * @return The blob name
     */
    const std::string &get_name() const
    {
        return name;
    }

    //@}

    /**@name Inserting data into a DevicePipeBlob
     */
    //@{
    /**
     * Insert data into a data blob
     *
     * According to the data to be inserted into the  blob data element, several kinds of insetor methods have been
     * implemented. You can insert data from:
     * @li Scalar data type
     * @li vector
     * @li TANGO CORBA sequence types (by reference)
     * @li TANGO CORBA sequence types (by pointer)
     * @li DataElement<T> with T being scalar data type
     * @li DataElement<T> with T being vector
     * @li DataElement<T> with T being TANGO CORBA sequence type (by reference)
     * @li DataElement<T> with T being TANGO CORBA sequence type (by pointer)
     *
     * When inserting data using a DataElement<T> instance, the data element name is also set.
     * <B>For insertion from TANGO CORBA sequence type pointer, the insertion method consumes the
     * memory allocated to store the data and it will be freed by the Tango layer.</B>
     *
     * Insert operators for the following scalar C++ types (and DataElement<T>)
     * @li bool
     * @li short
     * @li DevLong
     * @li DevLong64
     * @li float
     * @li double
     * @li unsigned char
     * @li unsigned short
     * @li DevULong
     * @li DevULong64
     * @li DevString
     * @li std::string
     * @li DevState
     * @li DevEncoded
     *
     * Insert operators for the following C++ vector types  (and DataElement<T>)
     * @li std::vector<bool>
     * @li std::vector<short>
     * @li std::vector<DevLong>
     * @li std::vector<DevLong64>
     * @li std::vector<float>
     * @li std::vector<double>
     * @li std::vector<unsigned char>
     * @li std::vector<unsigned short>
     * @li std::vector<DevULong>
     * @li std::vector<DevULong64>
     * @li std::vector<DevSstring>
     * @li std::vector<std::string>
     * @li std::vector<DevState>
     *
     * Insert operators for the following CORBA sequence types (and DataElement<T>):
     * @li DevVarBooleanArray &
     * @li DevVarShortArray &
     * @li DevVarLongArray &
     * @li DevVarLong64Array &
     * @li DevVarFloatArray &
     * @li DevVarDoubleArray &
     * @li DevVarUCharArray &
     * @li DevVarUShortArray &
     * @li DevVarULongArray &
     * @li DevVarULong64Array &
     * @li DevVarStringArray &
     * @li DevVarStateArray &
     *
     * Insert operators for the following CORBA sequence types <B>with memory consumption</B>  (and DataElement<T>):
     * @li DevVarBooleanArray *
     * @li DevVarShortArray *
     * @li DevVarLongArray *
     * @li DevVarLong64Array *
     * @li DevVarFloatArray *
     * @li DevVarDoubleArray *
     * @li DevVarUCharArray *
     * @li DevVarUShortArray *
     * @li DevVarULongArray *
     * @li DevVarULong64Array *
     * @li DevVarStringArray *
     * @li DevVarStateArray *
     *
     * Here is an example of inserting data into a DevicePipeBlob instance. We insert
     * 3 data element into the pipe blob with a DevLong, a vector of doubles and finally an array of 100 unsigned short
     * @code
     * DevicePipeBlob dpb("MyBlob");
     *
     * std::vector<std::string> de_names = {"FirstDE","SecondDE","ThirdDE"};
     * dpb.set_data_elt_names(de_names);
     *
     * DevLong dl = 666;
     * std::vector<double> v_db = {1.11,2.22};
     * unsigned short *array = new unsigned short [100];     // The array is populated by a way or another
     *
     * DevVarUShortArray *dvush = create_DevVarUShortArray(array,100);
     *
     * try
     * {
     *    dpb << dl << v_db << dvush;
     * }
     * catch (DevFailed &e)
     * {
     *    std::cout << "DevicePipeBlob insertion failed" << std::endl;
     *    ....
     * }
     *
     * @endcode
     * The same example of inserting data into a DevicePipeBlob instance when we want to set the data element name.
     * @code
     * DevicePipeBlob dpb("MyBlob");
     *
     * DataElement<DevLong> de_dl("FirstDE",666);
     *
     * std::vector<double> v_db = {1.11,2.22};
     * DataElement<std::vector<double> > de_v_db("SecondDE",v_db);
     *
     * unsigned short *array = new unsigned short [100];     // The array is populated by a way or another
     * DevVarUShortArray *dvush = create_DevVarUShortArray(array,100);
     * DataElement<DevVarUShortArray *> de_dvush("ThirdDE",array);
     *
     * try
     * {
     *    dpb << de_dl << de_v_db << de_dvush;
     * }
     * catch (DevFailed &e)
     * {
     *    std::cout << "DevicePipeBlob insertion failed" << std::endl;
     *    ....
     * }
     *
     * ...
     * @endcode
     * It is also possible to do the insertion in a third way
     * @code
     * DevicePipeBlob dpb("MyBlob");
     *
     * std::vector<std::string> de_names{"FirstDE","SecondDE","ThirdDE"};
     * dpb.set_data_elt_names(de_names);
     *
     * DevLong dl = 666;
     * std::vector<double> v_db = {1.11,2.22};
     * unsigned short *array = new unsigned short [100];     // The array is populated by a way or another
     *
     * DevVarUShortArray *dvush = create_DevVarUShortArray(array,100);
     *
     * dpb["FirstDE"] << dl;
     * dpb["SecondDE"] << v_db;
     * dpb["ThirdDE"] << dvush;
     *
     * @endcode
     *
     * @param [in] datum The data to be inserted into the DevicePipeBlob
     * @exception WrongData if requested
     */
    DevicePipeBlob &operator<<(const short &datum);
    /**
     * Set blob data element number
     *
     * Set the blob data element number
     *
     * @param [in] nb The blob data element number
     */
    void set_data_elt_nb(size_t nb);
    /**
     * Set blob data element number and names
     *
     * Set the blob data element number and names. The data element number is the number of names in the input
     * parameter.
     *
     * @param [in] names The blob data element names
     */
    void set_data_elt_names(const std::vector<std::string> &names);
    //@}

    /**@name Extracting data from a DevicePipeBlob
     */
    //@{
    /**
     * Extract data from a data blob
     *
     * According to the data inside blob data element, several kinds of extractor methods have been implemented. You
     * can extract data into:
     * @li Scalar data type
     * @li std::vector
     * @li TANGO CORBA sequence types
     * @li DataElement<T> with T being scalar data type
     * @li DataElement<T> with T being std::vector
     * @li DataElement<T> with T being TANGO CORBA sequence type
     *
     * When extracting data using a DataElement<T> instance, the data element name is also returned.
     * <B>For extraction into C++ vector, data are copied into the vector. It is not the case for extraction into TANGO
     * CORBA sequence type. For extraction into TANGO CORBA sequence types, the extraction method consumes the
     * memory allocated to store the data and it is the caller responsibility to delete this memory.</B>
     *
     * Extract operators for the following scalar C++ types (and DataElement<T>)
     * @li bool
     * @li short
     * @li DevLong
     * @li DevLong64
     * @li float
     * @li double
     * @li unsigned char
     * @li unsigned short
     * @li DevULong
     * @li DevULong64
     * @li std::string
     * @li DevState
     * @li DevEncoded
     *
     * Extract operators for the following C++ vector types  (and DataElement<T>)
     * @li std::vector<bool>
     * @li std::vector<short>
     * @li std::vector<DevLong>
     * @li std::vector<DevLong64>
     * @li std::vector<float>
     * @li std::vector<double>
     * @li std::vector<unsigned char>
     * @li std::vector<unsigned short>
     * @li std::vector<DevULong>
     * @li std::vector<DevULong64>
     * @li std::vector<std::string>
     * @li std::vector<DevState>
     *
     * Extract operators for the following CORBA sequence types <B>with memory consumption</B>  (and DataElement<T>):
     * @li DevVarBooleanArray *
     * @li DevVarShortArray *
     * @li DevVarLongArray *
     * @li DevVarLong64Array *
     * @li DevVarFloatArray *
     * @li DevVarDoubleArray *
     * @li DevVarUCharArray *
     * @li DevVarUShortArray *
     * @li DevVarULongArray *
     * @li DevVarULong64Array *
     * @li DevVarStringArray *
     * @li DevVarStateArray *
     *
     * Here is an example of extracting data from a DevicePipeBlob instance. We know that the DevicePipeBlob contains
     * 3 data element with a DevLong, an array of doubles and finally an array of unsigned short
     * @code
     * DevicePipeBlob dpb = .....
     *
     * DevLong dl;
     * std::vector<double> v_db;
     * DevVarUShortArray *dvush = new DevVarUShortArray();
     *
     * try
     * {
     *    dpb >> dl >> v_db >> dvush;
     * }
     * catch (DevFailed &e)
     * {
     *    std::cout << "DevicePipeBlob extraction failed" << std::endl;
     *    ....
     * }
     *
     * delete dvush;
     * @endcode
     * The same example of extracting data from a DevicePipeBlob instance when we want to retrieve the data element
     * name.
     * @code
     * DevicePipeBlob dpb = .....
     *
     * DataElement<DevLong> de_dl;
     * DataElement<std::vector<double> > de_v_db;
     * DataElement<DevVarUShortArray *> de_dvush(new DevVarUShortArray());
     *
     * try
     * {
     *    dpb >> de_dl >> de_v_db >> de_dvush;
     * }
     * catch (DevFailed &e)
     * {
     *    std::cout << "DevicePipeBlob extraction failed" << std::endl;
     *    ....
     * }
     *
     * std::cout << "Data element name = " << de_dl.name << " - Value = " << de_dl.value << std::endl;
     * ...
     * delete de_dvush.value;
     * @endcode
     * It is also possible to do the extraction in a generic way
     * @code
     * DevicePipeBlob dpb = .....
     *
     * size_t nb_de = dpb.get_data_elt_nb();
     * for (size_t loop = 0;loop < nb;loop++)
     * {
     *     int data_type = dpb.get_data_elt_type(loop);
     *     std::string de_name = dpb.get_data_elt_name(loop);
     *     switch(data_type)
     *     {
     *        case DEV_LONG:
     *        {
     *            DevLong lg;
     *            dpb >> lg;
     *        }
     *        break;
     *
     *        case DEVVAR_DOUBLEARRAY:
     *        {
     *            std::vector<double> v_db;
     *            dpb >> v_db;
     *        }
     *        break;
     *        ....
     *     }
     * ...
     * }
     * @endcode
     * Note that instead of using DevLong and std::vector<double> data, the extraction can be done using DataElement<T>
     * instances. In this case, the call to the get_data_elt_name() method becomes useless.
     *
     * @param [out] datum The blob data
     * @exception WrongData if requested
     */
    DevicePipeBlob &operator>>(short &datum);
    /**
     * Get blob data element number
     *
     * Get the blob data element number
     *
     * @return The blob data element number
     */
    size_t get_data_elt_nb();
    /**
     * Get blob data elements name
     *
     * Get the blob data elements name
     *
     * @return The blob data elements name
     */
    std::vector<std::string> get_data_elt_names();
    /**
     * Get blob data element name
     *
     * Get the blob data element name for a single data element
     *
     * @param [in] ind The data element index within the blob
     * @return The blob data element name
     */
    std::string get_data_elt_name(size_t ind);
    /**
     * Get blob data element value type
     *
     * Get the blob data element value type for a single data element
     *
     * @param [in] ind The data element index within the blob
     * @return The blob data element value type
     */
    int get_data_elt_type(size_t ind);

    //@}

    /**@name Exception and error related methods methods
     */
    //@{
    /**
     * Set exception flag
     *
     * It's a method which allows the user to switch on/off exception throwing when trying to extract data from a
     * DevicePipeBlob object. The following flags are supported :
     * @li @b isempty_flag - throw a WrongData exception (reason = API_EmptyDataElement) if user
     *       tries to extract data from one empty blob data element. By default, this flag
     *       is set
     * @li @b wrongtype_flag - throw a WrongData exception (reason = API_IncompatibleArgumentType) if user
     *       tries to extract data with a type different than the type used for insertion. By default, this flag
     *       is set
     * @li @b notenoughde_flag - throw a WrongData exception (reason = API_PipeWrongArg) if user
     *       tries to extract data from a DevicePipeBlob for a data element which does not exist. By default, this flag
     *       is set
     * @li @b blobdenamenotset_flag - Throw a WrongData exception (reason = API_PipeNoDataElement) if user tries to
     *       insert data into the blob while the name or number of data element has not been set with methods
     *       set_data_elt_nb() or set_data_elt_names()
     * @li @b mixing_flag - Throw a WrongData exception (reason = API_NotSupportedFeature) if user tries to mix
     *          insertion/extraction method (<< or >>) with operator[]
     *
     * @param [in] fl The exception flag
     */
    void exceptions(std::bitset<numFlags> fl)
    {
        exceptions_flags = fl;
    }

    /**
     * Get exception flag
     *
     * Returns the whole exception flags.
     * The following is an example of how to use these exceptions related methods
     * @code
     * DevicePipeBlob dpb;
     *
     * std::bitset<DevicePipeBlob::numFlags> bs = dpb.exceptions();
     * std::cout << "bs = " << bs << std::endl;
     *
     * dpb.set_exceptions(DevicePipeBlob::wrongtype_flag);
     * bs = dpb.exceptions();
     *
     * std::cout << "bs = " << bs << std::endl;
     * @endcode
     *
     * @return The exception flag
     */
    std::bitset<numFlags> exceptions()
    {
        return exceptions_flags;
    }

    /**
     * Reset one exception flag
     *
     * Resets one exception flag
     *
     * @param [in] fl The exception flag
     */
    void reset_exceptions(except_flags fl)
    {
        exceptions_flags.reset((size_t) fl);
    }

    /**
     * Set one exception flag
     *
     * Sets one exception flag. See DevicePipeBlob::exceptions() for a usage example.
     *
     * @param [in] fl The exception flag
     */
    void set_exceptions(except_flags fl)
    {
        exceptions_flags.set((size_t) fl);
    }

    /**
     * Check insertion/extraction success
     *
     * Allow the user to check if insertion/extraction into/from DevicePipeBlob instance was successfull. This
     * method has to be used when exceptions are disabled.
     *
     * @return True if insertion/extraction has failed
     */
    bool has_failed();

    /**
     * Get instance insertion/extraction state
     *
     * Allow the user to find out what was the reason of insertion/extraction into/from DevicePipeBlob failure. This
     * method has to be used when exceptions are disabled.
     * Here is an example of how methods has_failed() and state() could be used
     * @code
     * DevicePipeBlob dpb = ....
     *
     * std::bitset<DevicePipeBlob::numFlags> bs;
     * bs.reset();
     * dpb.exceptions(bs);
     *
     * DevLong dl;
     * dpb >> dl;
     *
     * if (dpb.has_failed() == true)
     * {
     *    std::bitset<DevicePipeBlob::numFlags> bs_err = dpb.state();
     *    if (bs_err.test(DevicePipeBlob::isempty_flag) == true)
     *        .....
     * }
     * @endcode
     *
     * @return The error bit set.
     */
    std::bitset<numFlags> state()
    {
        return ext_state;
    }

    //@}

    ///@privatesection
    ~DevicePipeBlob();
    DevicePipeBlob(const DevicePipeBlob &);
    DevicePipeBlob &operator=(const DevicePipeBlob &);
    DevicePipeBlob(DevicePipeBlob &&);
    DevicePipeBlob &operator=(DevicePipeBlob &&);

    DevicePipeBlob &operator<<(const DevBoolean &);
    //    DevicePipeBlob & operator << (const short &);
    DevicePipeBlob &operator<<(const DevLong &);
    DevicePipeBlob &operator<<(const DevLong64 &);
    DevicePipeBlob &operator<<(const float &);
    DevicePipeBlob &operator<<(const double &);
    DevicePipeBlob &operator<<(const DevUChar &);
    DevicePipeBlob &operator<<(const DevUShort &);
    DevicePipeBlob &operator<<(const DevULong &);
    DevicePipeBlob &operator<<(const DevULong64 &);
    DevicePipeBlob &operator<<(const DevString &);
    DevicePipeBlob &operator<<(const DevState &);
    DevicePipeBlob &operator<<(const DevEncoded &);
    DevicePipeBlob &operator<<(const std::string &);

    DevicePipeBlob &operator<<(const DevicePipeBlob &);

    DevicePipeBlob &operator<<(const std::vector<DevBoolean> &);
    DevicePipeBlob &operator<<(std::vector<short> &);
    DevicePipeBlob &operator<<(std::vector<DevLong> &);
    DevicePipeBlob &operator<<(std::vector<DevLong64> &);
    DevicePipeBlob &operator<<(std::vector<float> &);
    DevicePipeBlob &operator<<(std::vector<double> &);
    DevicePipeBlob &operator<<(std::vector<DevUChar> &);
    DevicePipeBlob &operator<<(std::vector<DevUShort> &);
    DevicePipeBlob &operator<<(std::vector<DevULong> &);
    DevicePipeBlob &operator<<(std::vector<DevULong64> &);
    DevicePipeBlob &operator<<(std::vector<DevString> &);
    DevicePipeBlob &operator<<(std::vector<DevState> &);
    DevicePipeBlob &operator<<(std::vector<DevEncoded> &);
    DevicePipeBlob &operator<<(const std::vector<std::string> &);

    DevicePipeBlob &operator<<(DevVarBooleanArray &);
    DevicePipeBlob &operator<<(DevVarShortArray &);
    DevicePipeBlob &operator<<(DevVarLongArray &);
    DevicePipeBlob &operator<<(DevVarLong64Array &);
    DevicePipeBlob &operator<<(DevVarFloatArray &);
    DevicePipeBlob &operator<<(DevVarDoubleArray &);
    DevicePipeBlob &operator<<(DevVarUCharArray &);
    DevicePipeBlob &operator<<(DevVarUShortArray &);
    DevicePipeBlob &operator<<(DevVarULongArray &);
    DevicePipeBlob &operator<<(DevVarULong64Array &);
    DevicePipeBlob &operator<<(DevVarStringArray &);
    DevicePipeBlob &operator<<(DevVarStateArray &);
    DevicePipeBlob &operator<<(DevVarEncodedArray &);

    DevicePipeBlob &operator<<(DevVarBooleanArray *);
    DevicePipeBlob &operator<<(DevVarShortArray *);
    DevicePipeBlob &operator<<(DevVarLongArray *);
    DevicePipeBlob &operator<<(DevVarLong64Array *);
    DevicePipeBlob &operator<<(DevVarFloatArray *);
    DevicePipeBlob &operator<<(DevVarDoubleArray *);
    DevicePipeBlob &operator<<(DevVarUCharArray *);
    DevicePipeBlob &operator<<(DevVarUShortArray *);
    DevicePipeBlob &operator<<(DevVarULongArray *);
    DevicePipeBlob &operator<<(DevVarULong64Array *);
    DevicePipeBlob &operator<<(DevVarStringArray *);
    DevicePipeBlob &operator<<(DevVarStateArray *);
    DevicePipeBlob &operator<<(DevVarEncodedArray *);

    //-------------------------------------------------------------------------------------------------

    DevicePipeBlob &operator>>(DevBoolean &);
    //    DevicePipeBlob & operator >> (short &);
    DevicePipeBlob &operator>>(DevLong &);
    DevicePipeBlob &operator>>(DevLong64 &);
    DevicePipeBlob &operator>>(float &);
    DevicePipeBlob &operator>>(double &);
    DevicePipeBlob &operator>>(DevUChar &);
    DevicePipeBlob &operator>>(DevUShort &);
    DevicePipeBlob &operator>>(DevULong &);
    DevicePipeBlob &operator>>(DevULong64 &);
    DevicePipeBlob &operator>>(DevString &);
    DevicePipeBlob &operator>>(DevState &);
    DevicePipeBlob &operator>>(DevEncoded &);
    DevicePipeBlob &operator>>(std::string &);

    DevicePipeBlob &operator>>(DevicePipeBlob &);

    DevicePipeBlob &operator>>(std::vector<DevBoolean> &);
    DevicePipeBlob &operator>>(std::vector<short> &);
    DevicePipeBlob &operator>>(std::vector<DevLong> &);
    DevicePipeBlob &operator>>(std::vector<DevLong64> &);
    DevicePipeBlob &operator>>(std::vector<float> &);
    DevicePipeBlob &operator>>(std::vector<double> &);
    DevicePipeBlob &operator>>(std::vector<DevUChar> &);
    DevicePipeBlob &operator>>(std::vector<DevUShort> &);
    DevicePipeBlob &operator>>(std::vector<DevULong> &);
    DevicePipeBlob &operator>>(std::vector<DevULong64> &);
    DevicePipeBlob &operator>>(std::vector<std::string> &);
    DevicePipeBlob &operator>>(std::vector<DevState> &);
    //    DevicePipeBlob & operator >> (std::vector<DevEncoded> &);

    DevicePipeBlob &operator>>(DevVarBooleanArray *);
    DevicePipeBlob &operator>>(DevVarShortArray *);
    DevicePipeBlob &operator>>(DevVarLongArray *);
    DevicePipeBlob &operator>>(DevVarLong64Array *);
    DevicePipeBlob &operator>>(DevVarFloatArray *);
    DevicePipeBlob &operator>>(DevVarDoubleArray *);
    DevicePipeBlob &operator>>(DevVarUCharArray *);
    DevicePipeBlob &operator>>(DevVarUShortArray *);
    DevicePipeBlob &operator>>(DevVarULongArray *);
    DevicePipeBlob &operator>>(DevVarULong64Array *);
    DevicePipeBlob &operator>>(DevVarStringArray *);
    DevicePipeBlob &operator>>(DevVarStateArray *);
    DevicePipeBlob &operator>>(DevVarEncodedArray *);

    DevicePipeBlob &operator[](const std::string &);

    const char *get_current_delt_name()
    {
        return (*extract_elt_array)[extract_ctr].name.in();
    }

    void set_current_delt_name(const std::string &);

    size_t get_extract_ind_from_name(const std::string &);
    size_t get_insert_ind_from_name(const std::string &);

    void reset_insert_ctr()
    {
        insert_ctr = 0;
    }

    DevVarPipeDataEltArray *get_insert_data() const
    {
        return insert_elt_array;
    }

    const DevVarPipeDataEltArray *get_extract_data() const
    {
        return extract_elt_array;
    }

    void set_extract_data(const DevVarPipeDataEltArray *_ptr)
    {
        extract_elt_array = _ptr;
    }

    void reset_insert_data_ptr()
    {
        insert_elt_array = nullptr;
    }

    void reset_extract_ctr()
    {
        extract_ctr = 0;
    }

    void set_extract_delete(bool _b)
    {
        extract_delete = _b;
    }

    void print(std::ostream &, int, bool) const;

  protected:
    ///@privatesection
    void throw_type_except(const std::string &, const std::string &);
    void throw_too_many(const std::string &, bool);
    void throw_is_empty(const std::string &);
    void throw_name_not_set(const std::string &);
    void throw_mixing(const std::string &);

  private:
    std::string name;                       // The blob name
    std::bitset<numFlags> exceptions_flags; // Exception flag
    std::bitset<numFlags> ext_state;        // Extraction state
    bool failed;                            // Failed flag

    DevVarPipeDataEltArray *insert_elt_array; // Ptr for data to be inserted (client write/Server read)
    int insert_ctr;                           // Ctr for inserting data elt
    int insert_ind;

    const DevVarPipeDataEltArray *extract_elt_array; // Ptr for data to be extracted (client read/Server write)
    int extract_ctr;                                 // Ctr for extracting data elt
    bool extract_delete;                             // Flag to force extract ptr delete
    int extract_ind;

    class DevicePipeBlobExt
    {
      public:
        DevicePipeBlobExt() { }
    };

    std::unique_ptr<DevicePipeBlobExt> ext;
};

//
// For DevicePipeBlob extraction
//

template <typename T>
DevicePipeBlob &operator>>(DevicePipeBlob &, T &);

template <typename T>
DevicePipeBlob &operator>>(DevicePipeBlob &, T *);

template <typename T>
DevicePipeBlob &operator>>(DevicePipeBlob &, DataElement<T> &);

//
// For DevicePipeBlob insertion
//

template <typename T>
DevicePipeBlob &operator<<(DevicePipeBlob &, T &);

template <typename T>
DevicePipeBlob &operator<<(DevicePipeBlob &, T *);

template <typename T>
DevicePipeBlob &operator<<(DevicePipeBlob &, DataElement<T> &);

} // namespace Tango
  //
#endif /* TANGO_CLIENT_DEVICEPIPEBLOB_H */
