TypePMT

= Polymorphic Type =

A new data type 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 message passing between blocks, as all of the data is of the same type, including the message. Tags also use PMTs as data type, so a stream tag can be of any logical data type. In a sense, PMTs are a way to extend C++' strict typing with something more flexible.

PMT Types
The 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 _.

The following constructors are available, all of which return pmt_t:

 pmt_bool

 pmt_symbol(const std::string &amp;)

 pmt_integer(long)

 pmt_real(double)

 pmt_complex(std::complex )

 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 &amp;)

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 Constants
There 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 Equality
To 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 _ - convert a C++ type to a PMT

 pmt_to _ - 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); In Python, you can use the pmt.to_python and pmt.to_pmt methods to convert, without having to know the type yourself (see below).

Checking PMT Length
For variable length PMT types, such as list and vector, you can use the following method to check how many elements are in the PMT:

 size_t pmt_length(pmt_t)

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

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 Vectors
Uniform 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, std::complex

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 )

 pmt_make_c64vector(size_t, std::complex )

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_ 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_writable_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

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:

 pmt_t pmt_make_dict

To set items in a dictionary, use:

 dict = pmt_dict_add(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:

 pmt_is_dict(pmt_t)

The following is an example of using dictionaries:

pmt_t p_dict = pmt_make_dict; // Empty dictionary

p_dict = pmt_dict_add(p_dict, pmt_symbol(&quot;number of dogs&quot;), pmt_integer(3)); p_dict = pmt_dict_add(p_dict, pmt_symbol(&quot;number of cats&quot;), pmt_integer(5)); p_dict = pmt_dict_add(p_dict, pmt_symbol(&quot;has a dog&quot;), PMT_T); p_dict = pmt_dict_add(p_dict, pmt_symbol(&quot;has a turtle&quot;), PMT_F);

if(pmt_is_dict(p_dict)) { pmt_t p_ndogs = pmt_dict_ref(p_dict, pmt_symbol(&quot;number of dogs&quot;), PMT_NIL); pmt_t p_ncats = pmt_dict_ref(p_dict, pmt_symbol(&quot;number of cats&quot;), PMT_NIL); pmt_t p_dog = pmt_dict_ref(p_dict, pmt_symbol(&quot;has a dog&quot;), PMT_NIL); pmt_t p_turtle = pmt_dict_ref(p_dict, pmt_symbol(&quot;has a turtle&quot;), PMT_NIL);

std::cout &lt;&lt; &quot;I have &quot; &lt;&lt; pmt_to_long(p_ndogs) &lt;&lt; &quot; dogs!\n&quot;; std::cout &lt;&lt; &quot;I have &quot; &lt;&lt; pmt_to_long(p_ncats) &lt;&lt; &quot; cats!\n&quot;;

if(pmt_eqv(p_dog, PMT_T)) std::cout &lt;&lt; &quot;I have a dog\n&quot;;      // This will be outputted else std::cout &lt;&lt; &quot; I do not have a dog\n&quot;;

if(pmt_eqv(p_turtle, PMT_T)) std::cout &lt;&lt; &quot;I have a turtle\n&quot;; else std::cout &lt;&lt; &quot;I do not have a turtle\n&quot;; // 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 (pmt_any_ref(p_any));

Conversion between Python Objects and PMTs
Although PMTs can be manipulating in python using the python versions of the C++ interfaces there are some additional goodies that make it easier to work with PMTs in python.

In particular there are functions to automate the conversion of python booleans, strings, integers, longs, floats, complex numbers, dictionaries, lists, tuples and combinations thereof into their equivalent PMTs.

Two functions capture most of this functionality.


 * pmt.to_pmt - Converts a python object to a PMT.
 * pmt.to_python - Converts a PMT into a python object.