/MEng/System/Runtime/MemBuf

ClassPath:MEng.System.Runtime.MemBuf
Parent ClassPath:MEng.Object
Copyable:Yes
Final:Yes

MEng.System.Runtime.MemBuf provides access to memory storage allocation. This is a potential security issue since a malicious macro could attempt to allocate memory until it used it all up and brought the workstation to a crawl. The application hosting the engine might, in a future implementation, set limits on the amount of allocated memory.

Buffers have a maximum size and are given an initial size when created. They will expand as required, up to the maximum size. You can give an initial size during construction, if you know the approximate or exact size that is going to be required. This is much more efficient, since it avoids having to expand the buffer. But, if necessary, the buffer will expand as required, as you access it. The optimum strategy is to figure out how much you need from the start and set the maximum to that amount and if you know you will need it all, set the initial size to that as well. This way you will never have to expand the buffer. If you know the maximum but not how much you will use, set the maximum to and set the initial to something very likely to be used and allow it to expand as required.

The current size to which the buffer has expanded is the 'allocation size'. You can read data out of the buffer within this portion, but if you attempt to read beyond that, you will get a BadIndex exception. You can write beyond this position and the buffer will just expand as required. But you will also get the BadIndex exception if you attempt to write past the maximum size.

Note that if, for instance, you have written bytes out to offset 100, then you write to the the buffer at offset 150, the bytes from offset 101 to 149 will not be set to any particular values unless you set them yourself. So they will contain garbage byte values.

 

Nested Classes:

Enum=MemBufErrors
    BadDigRange     : "%(1) is too large a range for digit extraction";
    BadIndex        : "Index %(1) is beyond the maximum buffer size ...
    BadInitSizes    : "The initial (%(1)) or max (%(2)) size was ...
    BadReallocSize  : "The realloc size (%(1)) is larger than the max ...
    BadValue        : "Could not convert the %(1) bytes...
    ByteRange       : "The source value is > 255";
    NotDecDig       : "The value at offset %(1) is not an ASCII decimal digit";
    NotHexDig       : "The value at offset %(1) is not an ASCII hex digit";
    Overflow        : "The start index (%(1)) plus the size (%(2)) ...
EndEnum;

This enumerated type defines the memory buffer specific exceptions that this class might throw. Note though that other exceptions might be thrown from other classes used by this class or passed into the methods of this class, and some common exceptions from MEng.Object might be thrown. The tokens will be replaced with the actual values at runtime.

 

Constructors:

Constructor(In] MEng.Card4 InitSize[In] MEng.Card4 MaxSize);

There is one constructor which takes an initial allocation size for the buffer. Note that the actual underlying buffer might be allocated larger than this, since sizes are sometimes rounded to various binary sizes, but it will be at least the indicated size.

If you know the amount of memory needed, exactly or approximately, then set that in the constructor, so that the buffer won't keep expanding automatically. If you don't know, then give it some reasonable initial size and allow it to expand as required.

 

Final, Const Methods:

CalcSum
(
    [In] MEng.Card4 StartInd
    , [In] MEng.Card4 Count
) Returns MEng.Card4;

This method will do a sum of Count bytes starting at the indicated start index. It will just let the sum overflow but since the accumulator is a Card4 value, it's not likely to happen.

CopyOut
(
    [Out] MEng.System.Runtime.MemBuf TargetBuf
    , [In] MEng.Card4 Count
    , [In] MEng.Card4 StartOfs
);

This method will copy data out of this buffer into the target buffer. It will copy Count bytes from this buffer, starting at StartOfs offset in this buffer. If the start offset or that offset plus the count would exceed the allocation size of this buffer, an exception will be thrown. If the count is larger than the maximum size of the target buffer, and exception will be thrown, else the target buffer will expand if necessary to hold the new data. 

ExportString(Out] MEng.String ToFill, [In] MEng.Card4 Count);
ExportStringAt(Out] MEng.String ToFill, [In] MEng.Card4 Count, [In] MEng.Card4 At);

This method will do a cheap ASCII to Unicode transcode of data out of this buffer to the passed string. ExportString starts at index zero in this buffer, and ExportStringAt let's you indicate where in this buffer to start exporting. The string is always filled from the 0th character. If the source is not ASCII, then results will be undefined.

In either case, if the starting source index plus the count of characters would exceed the current size of this buffer, then the Overflow exception will be thrown.

ExtractDecDigAt([In] MEng.Card4 Ofs) Returns MEng.Card4;
ExtractDecValAt([In] MEng.Card4 Ofs, [In] MEng.Card4 Len) Returns MEng.Card4;
ExtractHexDigAt([In] MEng.Card4 Ofs) Returns MEng.Card4;
ExtractHexValAt([In] MEng.Card4 Ofs, [In] MEng.Card4 Len) Returns MEng.Card4;

These methods are conveniences to perform a very common operation in device control, which is to extract a byte or range of bytes from a memory buffer which contains decimal or hexadecimal ASCII digits, and convert them to their binary representation. The Dig versions get a single byte, which is expected to hold a single ASCII decimal or hexadecimal digit value and converts it. The Val versions let you pull out a whole numerical value at once by indicating how many characters, starting at the start offset, you want to consider part of the number. Really the Dig versions are just conveniences which call the other and pass 1 as the length.

The binary value of the digit is returned as a Card4 value. If the byte extracted cannot be converted, because it is not a legal decimal or hexadecimal value, then one of the NotDecDigit or NotHexDigit exceptions will be thrown. If the individual bytes are all legal values for the radix, but the value cannot be converted, because perhaps it is too large, a BadValue exception is thrown.

FindByte([In] MEng.Card4 StartOfs, [In] MEng.Card1 ToFind) Returns MEng.Card4;

Starting at the passed start offset, this method will try to find the next byte that has the value passed in the ToFind parameter. If one is found, the offset is returned. If none is found, then Card4.kMaxValue is returned. The BadIndex exception will be thrown if the index is beyond the current allocation size.

GetCard1At([In] MEng.Card4 AtOfs) Returns MEng.Card1;
GetCard2At([In] MEng.Card4 AtOfs) Returns MEng.Card2;
GetCard4At([In] MEng.Card4 AtOfs) Returns MEng.Card4;
GetFloat4At([In] MEng.Card4 AtOfs) Returns MEng.Float4;
GetFloat8At([In] MEng.Card4 AtOfs) Returns MEng.Float8;
GetInt1At([In] MEng.Card4 AtOfs) Returns MEng.Int1;
GetInt2At([In] MEng.Card4 AtOfs) Returns MEng.Int2;
GetInt4At([In] MEng.Card4 AtOfs) Returns MEng.Int4;

These methods allow you to extract values of the fundamental numeric types from a particular position within the buffer. This is very useful in CQC device drivers in many cases, where a buffer of information is read in and you need to get values out of it. The BadIndex exception will be thrown if the index is beyond the current allocation size.

GetAlloc() Returns MEng.Card4;

Returns the current allocation size of the buffer, i.e. how far it has expanded so far. It might not be the exact size of the initial size given in the constructor, even if no expansion has occurred, since it might round the size up to some more efficient size, though always less than the maximum size.

GetMaxSize() Returns MEng.Card4;

Returns the maximum size of the buffer, i.e. the maximum size to which it can expand. This cannot be changed once set in the constructor.

 

Final, Non-Const Methods:

CopyIn
(
    [In] MEng.System.Runtime.MemBuf SrcBuf
    , [In] MEng.Card4 Count
    , [In] MEng.Card4 StartOfs
);

This method will copy data into this buffer from another buffer. It will copy Count bytes from the passed source buffer, starting at StartOfs offset within the source buffer. If the start offset or that offset plus the count would exceed the allocation size of the source, or the count would exceed this buffer's maximum size, an exception will be thrown. 

CopyInAt
(
    [In] MEng.System.Runtime.MemBuf SrcBuf
    , [In] MEng.Card4 Count
    , [In] MEng.Card4 AtOfs
);

This method will copy Count bytes from the source buffer, into this buffer, starting at the AtOfs.  If the at offset or that offset plus the count would exceed the maximum size of this buffer, or the count would exceed the allocation size of the source buffer, an exception will be thrown.

InsertASCIIHexPair
(
    [In]   MEng.Card1 ToInsert
    , [In] MEng.Card4 AtOfs
);

This method will take the passed Card1 value, format it to an ASCII two character value (with leading space if required), and put it into the memory buffer at the indicated offset. So if the parameters were 0x4 and 0, it would covert the first binary number parameter to the string " 4", then set byte zero to the ASCII space (0x20) and byte one to ASCII 4 (0x34).

PutCard1At([In] MEng.Card4 AtOfs, [In] MEng.Card1 ToPut);
PutCard2At([In] MEng.Card4 AtOfs, [In] MEng.Card2 ToPut);
PutCard4At([In] MEng.Card4 AtOfs, [In] MEng.Card4 ToPut);
PutFloat4At([In] MEng.Card4 AtOfs, [In] MEng.Float4 ToPut);
PutFloat8At([In] MEng.Card4 AtOfs, [In] MEng.Float8 ToPut);
PutInt1At([In] MEng.Card4 AtOfs, [In] MEng.Int1 ToPut);
PutInt2At([In] MEng.Card4 AtOfs, [In] MEng.Int2 ToPut);
PutInt4At([In] MEng.Card4 AtOfs, [In] MEng.Int4 ToPut);

These methods allow you to insert values of the fundamental numeric types into the buffer at a particular position. If the offset plus the size of the data is beyond the current allocation size, the buffer will expand to hold the new data, as long as it does not exceed the maximum size. The offset plus the size of the value inserted must be less than the maximum size of the buffer.

ImportString([In] MEng.String Src, [In] MEng.Card4 Count) Returns MEng.Card4;
ImportStringAt
(
    [In] MEng.String Src
    , [In] MEng.Card4 Count
    , [In] MEng.Card4 TarInd
) Returns MEng.Card4;

One very common operation in device drivers is to convert a string of text to their binary equivalents. This method will go through Count bytes of the Src string and for each character it will effectively do a GetOrdinal() on that character and store the binary value in the same index in this object.

If any character ordinal is greater than 255, then the ByteRange exception will be thrown. If you want to do all of the characters in the string, you can just pass Card4.kMaxValue and the actual length of the string will be used. The return value indicates how many characters were processed, which would be the same as passed in except in the case where you pass Card4.kMaxValue.

A second version is required that lets you indicate a starting target index into this object, i.e. instead of starting to import bytes into this object as index zero, you can start at, say, 15.

In either case, if the starting target index plus the count of characters would exceed the maximum allocation size of this buffer, then the Overflow exception will be thrown.

Reallocate([In] MEng.Card4 Reallocate);

Reallocates the buffer to the indicated size. This will throw away an current content, and allocate a new buffer internally. If the new size is smaller than the current size, it won't do anything and will keep the larger size. The new size cannot be larger than the maximum size set in the constructor, or an exception will be thrown.

SetAll([In] MEng.Card1 ToSet);

Sets all of the current allocated bytes of the buffer to the indicated value. Note that this will cause a full allocation of the buffer