AMQP-CPP/include/amqpcpp/table.h

306 lines
7.0 KiB
C++

/**
* AMQP field table
*
* @copyright 2014 - 2023 Copernica BV
*/
/**
* Include guard
*/
#pragma once
/**
* Dependencies
*/
#include "field.h"
#include "fieldproxy.h"
#include <cstddef>
#include <vector>
#include <map>
/**
* Set up namespace
*/
namespace AMQP {
/**
* AMQP field table
*/
class Table : public Field
{
private:
/**
* We define a custom type for storing fields
* @typedef FieldMap
*/
typedef std::map<std::string, std::unique_ptr<Field> > FieldMap;
/**
* Store the fields
* @var FieldMap
*/
FieldMap _fields;
public:
/**
* Constructor that creates an empty table
*/
Table() {}
/**
* Decode the data from a received frame into a table
*
* @param frame received frame to decode
*/
Table(InBuffer &frame);
/**
* Copy constructor
* @param table
*/
Table(const Table &table);
/**
* Move constructor
* @param table
*/
Table(Table &&table) : _fields(std::move(table._fields)) {}
/**
* Destructor
*/
virtual ~Table() {}
/**
* Assignment operator
* @param table
* @return Table
*/
Table &operator=(const Table &table);
/**
* Move assignment operator
* @param table
* @return Table
*/
Table &operator=(Table &&table);
/**
* Retrieve all keys in the table
*
* @return Vector with all keys in the table
*/
std::vector<std::string> keys() const;
/**
* Create a new instance on the heap of this object, identical to the object passed
* @return Field*
*/
virtual std::unique_ptr<Field> clone() const override
{
return std::unique_ptr<Table>(new Table(*this));
}
/**
* Get the size this field will take when
* encoded in the AMQP wire-frame format
*/
virtual size_t size() const override;
/**
* Set a field
* @param name field name
* @param value field value
* @return Table
*/
Table &set(const std::string& name, const Field &value)
{
// copy to a new pointer and store it
_fields[name] = value.clone();
// allow chaining
return *this;
}
/**
* Aliases for setting values
* @param name
* @param value
* @return Table&
*/
Table &set(const std::string &name, bool value) { return set(name, BooleanSet(value)); }
Table &set(const std::string &name, uint8_t value) { return set(name, UOctet(value)); }
Table &set(const std::string &name, int8_t value) { return set(name, Octet(value)); }
Table &set(const std::string &name, uint16_t value) { return set(name, UShort(value)); }
Table &set(const std::string &name, int16_t value) { return set(name, Short(value)); }
Table &set(const std::string &name, uint32_t value) { return set(name, ULong(value)); }
Table &set(const std::string &name, int32_t value) { return set(name, Long(value)); }
Table &set(const std::string &name, uint64_t value) { return set(name, ULongLong(value)); }
Table &set(const std::string &name, int64_t value) { return set(name, LongLong(value)); }
Table &set(const std::string &name, const std::string &value) { return set(name, LongString(value)); }
Table &set(const std::string &name, const std::string_view &value) { return set(name, LongString(value)); }
Table &set(const std::string &name, const char *value) { return set(name, LongString(std::string(value))); }
Table &set(const std::string &name, std::nullptr_t) { return set(name, VoidField()); }
/**
* Clear the entire table
* @return Table
*/
Table &clear()
{
_fields.clear();
return *this;
}
/**
* Is a certain field set in the table
* @param name
* @return bool
*/
bool contains(const std::string &name) const
{
return _fields.find(name) != _fields.end();
}
/**
* Get a field
*
* If the field does not exist, an empty string field is returned
*
* @param name field name
* @return the field value
*/
const Field &get(const std::string &name) const;
/**
* Get a field
*
* @param name field name
*/
AssociativeFieldProxy operator[](const std::string& name)
{
return AssociativeFieldProxy(this, name);
}
/**
* Get a field
*
* @param name field name
*/
AssociativeFieldProxy operator[](const char *name)
{
return AssociativeFieldProxy(this, name);
}
/**
* Get a const field
*
* @param name field name
*/
const Field &operator[](const std::string& name) const
{
return get(name);
}
/**
* Get a const field
*
* @param name field name
*/
const Field &operator[](const char *name) const
{
return get(name);
}
/**
* Write encoded payload to the given buffer.
* @param buffer
*/
virtual void fill(OutBuffer& buffer) const override;
/**
* Get the type ID that is used to identify this type of
* field in a field table
*/
virtual char typeID() const override
{
return 'F';
}
/**
* We are a table
*
* @return true, because we are a table
*/
bool isTable() const override
{
return true;
}
/**
* Output the object to a stream
* @param std::ostream
*/
virtual void output(std::ostream &stream) const override
{
// prefix
stream << "table(";
// is this the first iteration
bool first = true;
// loop through all members
for (auto &iter : _fields)
{
// split with comma
if (!first) stream << ",";
// show output
stream << iter.first << ":" << *iter.second;
// no longer first iter
first = false;
}
// postfix
stream << ")";
}
/**
* Cast to table.
*
* @note: This function may look silly and unnecessary. We are, after all, already
* a table. The whole reason we still have this function is that it is virtual
* and if we do not declare a cast to table on a pointer to base (i.e. Field)
* will return an empty field instead of the expected table.
*
* Yes, clang gets this wrong and gives incorrect warnings here. See
* https://llvm.org/bugs/show_bug.cgi?id=28263 for more information
*
* @return Ourselves
*/
virtual operator const Table& () const override
{
// this already is a table, so no cast is necessary
return *this;
}
};
/**
* Custom output stream operator
* @param stream
* @param field
* @return ostream
*/
inline std::ostream &operator<<(std::ostream &stream, const AssociativeFieldProxy &field)
{
// get underlying field, and output that
return stream << field.get();
}
/**
* end namespace
*/
}