BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsls_alignmenttotype

Detailed Description

Outline

Purpose

Provide a meta-function mapping an ALIGNMENT to a primitive type.

Classes

See also
bsls_alignmentfromtype

Description

This component provides a meta-function, bsls::AlignmentToType, parameterized on an integral ALIGNMENT, that declares a typedef (Type), which is an alias for a primitive type having the indicated ALIGNMENT requirement.

Usage

Consider a parameterized type, my_AlignedBuffer, that provides aligned memory to store a user-defined type. A my_AlignedBuffer object is useful in situations where efficient (e.g., stack-based) storage is required.

The my_AlignedBuffer union (defined below) takes a TYPE and the ALIGNMENT requirements for that type as template parameters, and provides an appropriately sized and aligned block of memory via the buffer functions. Note that my_AlignedBuffer ensures that the returned memory is aligned correctly for the specified size by using bsls::AlignmentToType<ALIGNMENT>::Type, which provides a primitive type having the ALIGNMENT requirement. The class definition of my_AlignedBuffer is as follows:

template <class TYPE, int ALIGNMENT>
union my_AlignedBuffer {
private:
// DATA
char d_buffer[sizeof(TYPE)];
typename bsls::AlignmentToType<ALIGNMENT>::Type d_align; // force
// alignment
public:
// MANIPULATORS
char *buffer();
// Return the address of the modifiable first byte of memory
// contained by this object as a 'char *' pointer.
TYPE& object();
// Return a reference to the modifiable 'TYPE' object stored in
// this buffer. The referenced object has an undefined state
// unless a valid 'TYPE' object has been constructed in this
// buffer.
// ACCESSORS
const char *buffer() const;
// Return the address of the non-modifiable first byte of memory
// contained by this object as a 'const char *' pointer.
const TYPE& object() const;
// Return a reference to the non-modifiable 'TYPE' object stored in
// this buffer. The referenced object has an undefined state
// unless a valid 'TYPE' object has been constructed in this
// buffer.
};
AlignmentImpPriorityToType< PRIORITY >::Type Type
Definition bsls_alignmenttotype.h:394

The function definitions of my_AlignedBuffer are as follows:

// MANIPULATORS
template <class TYPE, int ALIGNMENT>
inline
char *my_AlignedBuffer<TYPE, ALIGNMENT>::buffer()
{
return d_buffer;
}
template <class TYPE, int ALIGNMENT>
inline
TYPE& my_AlignedBuffer<TYPE, ALIGNMENT>::object()
{
return *reinterpret_cast<TYPE *>(this);
}
// ACCESSORS
template <class TYPE, int ALIGNMENT>
inline
const char *my_AlignedBuffer<TYPE, ALIGNMENT>::buffer() const
{
return d_buffer;
}
template <class TYPE, int ALIGNMENT>
inline
const TYPE& my_AlignedBuffer<TYPE, ALIGNMENT>::object() const
{
return *reinterpret_cast<const TYPE *>(this);
}

my_AlignedBuffer can be used to construct buffers for different types and with varied alignment requirements. Consider that we want to construct an object that stores the response of a floating-point operation. If the operation is successful, then the response object stores a double result; otherwise, it stores an error string of type string, which is based on the standard type string (see bslstl_string ). For the sake of brevity, the implementation of string is not explored here. Here is the definition for the Response class:

class Response {

To create a my_AlignedBuffer object we must specify the alignment value for our types. For simplicity, we use a maximum alignment value for all types (assumed to be 8 here):

enum { MAX_ALIGNMENT = 8 };

Note that we use my_AlignedBuffer to allocate sufficient, aligned memory to store the result of the operation or an error message:

private:
union {
my_AlignedBuffer<double, MAX_ALIGNMENT> d_result;
my_AlignedBuffer<string, MAX_ALIGNMENT> d_errorMessage;
};

The isError flag indicates whether the response object stores valid data or an error message:

bool d_isError;

Below we provide a simple public interface suitable for illustration only:

public:
// CREATORS
Response(double result);
// Create a response object that stores the specified 'result'.
Response(const string& errorMessage);
// Create a response object that stores the specified
// 'errorMessage'.
~Response();
// Destroy this response object.

The manipulator functions allow clients to update the response object to store either a double result or an error message:

// MANIPULATORS
void setResult(double result);
// Update this object to store the specified 'result'. After this
// operation 'isError' returns 'false'.
void setErrorMessage(const string& errorMessage);
// Update this object to store the specified 'errorMessage'. After
// this operation 'isError' returns 'true'.

The isError function informs clients whether a response object stores a result value or an error message:

// ACCESSORS
bool isError() const;
// Return 'true' if this object stores an error message, and
// 'false' otherwise.
double result() const;
// Return the result value stored by this object. The behavior is
// undefined unless 'false == isError()'.
const string& errorMessage() const;
// Return a reference to the non-modifiable error message stored by
// this object. The behavior is undefined unless
// 'true == isError()'.
};

Below we provide the function definitions. Note that we use the my_AlignedBuffer::buffer function to access correctly aligned memory. Also note that my_AlignedBuffer just provides the memory for an object; therefore, the Response class is responsible for the construction and destruction of the specified objects. Since our Response class is for illustration purposes only, we ignore exception-safety concerns; nor do we supply an allocator to the string constructor, allowing the default allocator to be used instead:

// CREATORS
Response::Response(double result)
{
new (d_result.buffer()) double(result);
d_isError = false;
}
Response::Response(const string& errorMessage)
{
new (d_errorMessage.buffer()) string(errorMessage);
d_isError = true;
}
Response::~Response()
{
if (d_isError) {
typedef string Type;
d_errorMessage.object().~Type();
}
}
// MANIPULATORS
void Response::setResult(double result)
{
if (!d_isError) {
d_result.object() = result;
}
else {
typedef string Type;
d_errorMessage.object().~Type();
new (d_result.buffer()) double(result);
d_isError = false;
}
}
void Response::setErrorMessage(const string& errorMessage)
{
if (d_isError) {
d_errorMessage.object() = errorMessage;
}
else {
new (d_errorMessage.buffer()) string(errorMessage);
d_isError = true;
}
}
// ACCESSORS
bool Response::isError() const
{
return d_isError;
}
double Response::result() const
{
assert(!d_isError);
return d_result.object();
}
const string& Response::errorMessage() const
{
assert(d_isError);
return d_errorMessage.object();
}

Clients of the Response class can use it as follows:

double value1 = 111.2, value2 = 92.5;
if (0 == value2) {
Response response("Division by 0");
// Return erroneous response
}
else {
Response response(value1 / value2);
// Process response object
}