Polymorphic Type
A new data type introduced for use with the new m-blocks, is a polymorphic data
type. The type can really be used to store anything, but also has simple
conversion methods for common data types such as bool, long, or a vector.
The polymorphic type simplifies the data passing between m-blocks, as all of
the data is of the same type, including the message. Overview:
PMT TypesThe
PMT library supports the following major types. Some of the more complex types
have their own wiki page for assistance.
- bool - just like a C++ boolean, true or false
- symbol - easiest to think of it as a std::string
- integer - int, long, unsigned
- real - double, float
- complex - gr_complex, std::complex
- null - NULL
- pair - a 2-tuple data type
- list - a list
- vector - a vector of PMT objects
- dict - a dictionary (hash) like structure
- uniform_vector - a vector of typed objects (uint8_t, float,
etc...)
- any - boost:any cast
Making a PMT instance
To make PMT, the data type pmt_t is used just like any other data
type. The following is an example:
pmt_t p_instance;
Constructing/Assigning a PMT
To construct or assign a value to a PMT, a method is available for each type
of the following syntax: pmt<type>_. The following
constructors are available, all of which return pmt_t:
- pmt_bool()
- pmt_symbol(const std::string &)
- pmt_integer(long)
- pmt_real(double)
- pmt_complex(std::complex<double>)
- pmt_null()
- pmt_pair() or pmt_pair(pmt,pmt)
- pmt_vector(size_t,pmt)
- pmt_dict()
- pmt_make_*vector(size_t, *) -- see uniform
vectors
- pmt_any(const boost::any &)
For example, pmt_integer(long)
returns a pmt_t, constructed from a long:
pmt_t p_num = pmt_integer(3);
Checking PMT Type
With a polymorphic type, it is useful to have methods to check what type it
actually is if unknown. The following methods are available for testing PMT
types, all of which return bool:
- pmt_is_bool(pmt)
- pmt_is_symbol(pmt)
- pmt_is_number(pmt)
- pmt_is_integer(pmt)
- pmt_is_real(pmt)
- pmt_is_complex(pmt)
- pmt_is_null(pmt)
- pmt_is_pair(pmt)
- pmt_is_vector(pmt)
- pmt_is_uniform_vector(pmt)
- pmt_is_dict(pmt)
- pmt_is_any(pmt)
In this example, test_pmt will be assigned
the value true:
pmt_t p_num = pmt_integer(3); bool test_pmt = pmt_is_integer(p_num);
PMT ConstantsThere are 3 main constant values in the PMT
world which can be returned:
- PMT_T - PMT representation of true
- PMT_F - PMT representation of false
- PMT_NIL - PMT NIL/NULL representation
When a PMT is initialized with no value, such as pmt_dict() ... it
is equivalent to PMT_NIL until it is assigned elements.
Testing EqualityTo test the equality of PMT types, the
following methods are available.
- pmt_eq(pmt_t, pmt_t) - tests strict equality (the two parameters
are the same)
- pmt_eqv(pmt_t, pmt_t) - tests for equivalence (the two parameters
have the same value)
- pmt_equal(pmt_t, pmt_t) - tests for equivalence of multi-value
types (pmt_pair, pmt_vector)
The following gives a good overview of
equality testing:
pmt_t p1 = pmt_integer(5); pmt_t p2 = pmt_integer(5); pmt_t p3 = pmt_integer(1);
pmt_eq(p1, p1); // Returns true pmt_eq(p1, p2); // Returns false
pmt_eqv(p1, p1); // Returns true pmt_eqv(p1, p2); // Returns true
pmt_t p3 = pmt_pair(p1, p1); pmt_t p4 = pmt_pair(p1, p2); pmt_t p5 = pmt_pair(p1, p3);
pmt_equal(p3, p4); // Returns true, equivalence in values pmt_equal(p3, p5); // Returns false, values are different
PMT Conversion Methods
There are simple methods to store common C++ types as PMT for use in passing
the data in m-block messages. All of the conversion methods are of a similar
syntax:
- pmt_from<type>_ - convert a C++ type to a PMT
- pmt_to<type>_ - convert a PMT to a C++ type
The
following C++ types are supported:
- bool, long, double, complex
For example:
pmt_t p_val = pmt_from_long(3); long l_val = pmt_to_long(p_val);
Checking PMT LengthFor variable length PMT types, such as
list and vector, you can use the following method to check how many elements are
in the PMT:
pmt_t p1 = pmt_integer(1); pmt_t p2 = pmt_integer(2); pmt_t p3 = pmt_integer(3);
pmt_t p_list = pmt_list3(p1, p2, p3);
pmt_length(p_list); // Returns 3
Detailed Type Information
Lists
PMT lists are as they sound, lists! Each list element is of type pmt_t, and
the list can be of infinite length. To create a base list, you can use the
following methods:
- pmt_list1(pmt_t)
- pmt_list2(pmt_t, pmt_t)
- pmt_list3(pmt_t, pmt_t, pmt_t)
- pmt_list4(pmt_t, pmt_t, pmt_t, ...)
- pmt_list5(pmt_t, pmt_t, pmt_t, ...)
- pmt_list6(pmt_t, pmt_t, pmt_t, ...)
Anything beyond 6, use an add,
which returns a new list:
- pmt_t pmt_list_add(pmt_t list, pmt_t object)
List items cannot be removed, as they are implemented as constants. To
access the nth element in a list, the following method is available which
returns the nth element:
- pmt_t pmt_nth(size_t n, pmt_t list)
The following exercises PMT
lists:
pmt_t p_list1 = pmt_list1(PMT_T); p_list1 = pmt_list_add(p_list1, PMT_F);
pmt_t p_list2 = pmt_list2(PMT_T, PMT_F);
pmt_equal(p_list1, p_list2); // Returns true
pmt_t p_element0 = pmt_nth(0, p_list2); // Access elements pmt_t p_element1 = pmt_nth(1, p_list2);
pmt_eqv(p_element0, PMT_T); // Returns true pmt_eqv(p_element1, PMT_F); // Returns true
Uniform VectorsUniform PMT vectors are for storing vectors of
common C++ types. The following types are supported:
- uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t,
float, double, std::complex<float>,
std::complex<double>
The following methods are used to create a
uniform vector, whose return types are pmt_t, where the first parameter
is the number of elements to create and the second parameter is a fill parameter
for initializing all of the elements to a specific value:
- pmt_make_u8vector(size_t, uint8_t)
- pmt_make_s8vector(size_t, int8_t)
- pmt_make_u16vector(size_t, uint16_t)
- pmt_make_s16vector(size_t, int16_t)
- pmt_make_u32vector(size_t, uint32_t)
- pmt_make_s32vector(size_t, int32_t)
- pmt_make_u64vector(size_t, uint64_t)
- pmt_make_s64vector(size_t, int64_t)
- pmt_make_f32vector(size_t, float);
- pmt_make_f64vector(size_t, double);
- pmt_make_c32vector(size_t, std::complex<float>)
- pmt_make_c64vector(size_t, std::complex<double>)
To get a
reference to each vector to access it like an array, you can use the following,
which takes a uniform vector as parameter 1, and a pointer to a size_t to return
the number of elements in the vector:
- pmt_<type>vector_ref(pmt_t, size_t)
The following is an
example of uniform vectors:
static const int nelements = 64; pmt_t s16vec = pmt_make_s16vector(nelements, 0); // Initializes all 64 elements to 0
size_t vec_size; int16_t *elements = pmt_s16vector_writeable_elements(s16vec, vec_size); // Returns pointer, vec_size is set to 64
// Now you can access the elements like a standard array for(int i=0; i<vec_size; i++) elements[i] = 1;
Dictionaries
A dictionary behaves exactly like a hash. PMT objects are referenced with a
pmt_symbol (string-like PMT type). To create a dictionary, use:
To set items in a dictionary, use:
- pmt_dict_set(pmt_t dict, pmt_t symbol, pmt_t value)
You can
reference items in a dictionary using the following, which returns a specified
error_val if the symbol (hash key) did not exist:
- pmt_dict_ref(pmt_t dict, pmt_t symbol, pmt_t error_val)
It is
always useful to check that a pmt_t is a dictionary before trying to reference
its elements to prevent exceptions:
The following is an example of using
dictionaries:
pmt_t p_dict = pmt_make_dict(); // Empty dictionary
pmt_dict_set(p_dict, pmt_symbol("number of dogs"), pmt_integer(3)); pmt_dict_set(p_dict, pmt_symbol("number of cats"), pmt_integer(5)); pmt_dict_set(p_dict, pmt_symbol("has a dog"), PMT_T); pmt_dict_set(p_dict, pmt_symbol("has a turtle"), PMT_F);
if(pmt_is_dict(p_dict)) { pmt_t p_ndogs = pmt_dict_ref(p_dict, pmt_symbol("number of dogs"), PMT_NIL); pmt_t p_ncats = pmt_dict_ref(p_dict, pmt_symbol("number of cats"), PMT_NIL); pmt_t p_dog = pmt_dict_ref(p_dict, pmt_symbol("has a dog"), PMT_NIL); pmt_t p_turtle = pmt_dict_ref(p_dict, pmt_symbol("has a turtle"), PMT_NIL);
std::cout << "I have " << pmt_to_long(p_ndogs) << " dogs!\n"; std::cout << "I have " << pmt_to_long(p_ncats) << " cats!\n";
if(pmt_eqv(p_dog, PMT_T)) std::cout << "I have a dog\n"; // This will be outputted else std::cout << " I do not have a dog\n";
if(pmt_eqv(p_turtle, PMT_T)) std::cout << "I have a turtle\n"; else std::cout << "I do not have a turtle\n"; // This will be outputted }
Any
When there is nothing to store your type, use a pmt_any. This allows you to
cast anything into a pmt_t using boost::any cast. Example:
typedef struct d_frame_hdr_t { long src_addr; long dst_addr; } +attribute+((+packed+));
d_frame_hdr_t my_header; my_header.src_addr = 3; my_header.dst_addr = 4;
pmt_t p_any = pmt_make_any(my_header);
// After extracting using pmt_any_ref the following will be true: // extract_header.src_addr == 3 // extract_header.dst_addr == 4 d_frame_hdr_t extract_header = boost::any_cast<d_frame_hdr_t> (pmt_any_ref(p_any));
注:Polymorphic Type(原文出处,翻译整理仅供参考!) |
|