A Cache is a dynamic input storage area. More...
#include <Cache.hh>
Public Types | |
typedef bool(* | Data_Test )(const void *) |
Data test function pointer. | |
Public Member Functions | |
Cache () | |
Constructs a default Cache. | |
Cache (unsigned long capacity, unsigned long data_margin=0, Data_Test data_test=NULL) | |
Constructs a Cache of a given capacity. | |
Cache (unsigned long capacity, std::istream &source, unsigned long data_margin=0, Data_Test data_test=NULL) | |
Constructs a Cache of a given capacity and data stream source. | |
virtual | ~Cache () |
Destroys the Cache. | |
Cache & | source (std::istream &source) |
Sets the data stream source used during a refill. | |
std::istream & | source () const |
Gets the data stream source. | |
unsigned long long | bytes_read () const |
Gets the total number of bytes read into the cache from the data source stream. | |
Cache & | data_margin (unsigned long amount) |
Sets the minimum amount of data to be retained during a drain. | |
unsigned long | data_margin () const |
Gets the size of the data margin that will be retained during a drain. | |
Cache & | data_test (Data_Test tester, unsigned long data_amount) |
Sets the end-of-data test function and the amount of data required for testing. | |
Data_Test | data_test () const |
Gets the end-of-data test function. | |
unsigned long | data_test_amount () const |
Gets the amount of data required by the end-of-data test function. | |
virtual void | drain () |
Drains the cache of consumed user data. | |
virtual bool | refill (unsigned long max_amount=(unsigned long)-1) |
Refills the cache from the data source stream. | |
virtual Cache & | put (char *data, unsigned long amount) |
Puts data into the cache storage. | |
virtual unsigned long | get (char *data, unsigned long amount) |
Gets data from the cache storage. | |
virtual void | reset () |
Resets the cache to its empty state. | |
unsigned long | capacity () const |
Gets the capacity of the data storage area. | |
Cache & | capacity (unsigned long amount) |
Sets the effective capacity of the data storage area. | |
unsigned long | amount_used () const |
Gets the amount of cache storage in use. | |
unsigned long | amount_free () const |
Gets the amount of free cache space. | |
char * | start () const |
Gets the starting address of the cache data storage area. | |
Cache & | next (char *location) |
Sets the location of the next user data. | |
char * | next () const |
Gets the address of the next user data. | |
unsigned long | amount_consumed () const |
Gets the amount of user data used (consumed). | |
long | amount_remaining () const |
Gets how much more user data is available. | |
char * | last () const |
Gets the address where the user data ends. | |
Cache & | last (char *location) |
Sets the location where the user data ends. | |
void | state_report (std::ostream &stream) const |
Generates a report on a stream of the current cache state. | |
void | state_report () const |
Generates a report on stdout of the current cache state. | |
Static Public Attributes | |
static const char *const | ID = "PIRL::Cache ($Revision: 1.10 $ $Date: 2010/11/11 20:41:40 $)" |
Class identification name with source code version and date. |
A Cache is a dynamic input storage area.
The storage capacity is zero or more bytes. A Cache of zero capacity has no storage allocated to it. Storage capacity will automatically inflate as needed. It can also be deflated if desired.
The available storage capacity is managed as a refillable user data space. The user data capacity may be set to less than the amount of allocated storage, but will inflate as needed.
The user data space is divided into used and free space, with the former in a contiguous section preceeding the latter. The used space can be logically drained, which will shift all user data following a specified next valid data location to the front of the user space and thus increasing the amount of free space. The free space can be refilled from an input stream bound the the Cache.
A data margin may be specified as the minimum amount of data to retain when the user space is drained. This supports the detection of a logical end-of-data during a refill following a drain by the automatic application of a user supplied data testing function that may require more than one datum. A generic data margin, distinct from any margin required by a data testing function, may be specified.
User data can be put directly into the free space, instead of doing a refill from a stream source, with the capacity automatically increasing as needed. To get an arbitrary amount of user data it will be copied sequentially starting from the next valid datum, with automatic drain and refill being used to obtain data as needed.
typedef bool(* PIRL::Cache::Data_Test)(const void *) |
Data test function pointer.
Pointer to a function that takes a data address and returns a condition. Used to test data for some condtion on the data.
Cache::Cache | ( | ) |
Constructs a default Cache.
The cache has no capacity (no storage is allocated). The data source is set to the standard input.
References capacity(), and reset().
Cache::Cache | ( | unsigned long | capacity, |
unsigned long | data_margin = 0 , |
||
Data_Test | data_test = NULL |
||
) | [explicit] |
Constructs a Cache of a given capacity.
The data source is set to the standard input.
capacity | The capacity, in bytes, of the data storage area. |
data_margin | The minimum amount of data to retain during a drain of the cache contents, or the amount of data required by the data_test function if the latter is non-NULL. |
data_test | A Data_Test function that is used to test for an end-of-data condition during a refill of the cache contents. |
Cache::Cache | ( | unsigned long | capacity, |
std::istream & | source, | ||
unsigned long | data_margin = 0 , |
||
Data_Test | data_test = NULL |
||
) |
Constructs a Cache of a given capacity and data stream source.
capacity | The capacity, in bytes, of the data storage area. |
source | The istream from which data will be obtained to refill the cache contents. |
data_margin | The minimum amount of data to retain during a drain of the cache contents, or the amount of data required by the data_test function if the latter is non-NULL. |
data_test | A Data_Test function that is used to test for an end-of-data condition during a refill of the cache contents. |
Cache::~Cache | ( | ) | [virtual] |
Destroys the Cache.
The data storage area is deleted.
Cache& PIRL::Cache::source | ( | std::istream & | source ) | [inline] |
Sets the data stream source used during a refill.
N.B.: The number of bytes read is not reset.
source | An istream that will be used as the source of data when the cache is refilled. |
References source().
Referenced by source().
std::istream& PIRL::Cache::source | ( | ) | const [inline] |
Gets the data stream source.
unsigned long long PIRL::Cache::bytes_read | ( | ) | const [inline] |
Gets the total number of bytes read into the cache from the data source stream.
If, during a refill, the stream is repositioned back to the location of an end-of-data condition the bytes logically returned to the stream are not counted as having been read.
Cache & Cache::data_margin | ( | unsigned long | amount ) |
Sets the minimum amount of data to be retained during a drain.
The Cache will always guarantee that at least the specified amount of data will remain after the Cache has been drained.
If the amount is non-zero then at least one additional byte must be provided for adding new data during a refill. Therefore, the capacity of the data storage area will be increased to the amount + 1, if necessary.
N.B.: If a Data_Test function has been provided, then the effective data margin amount may be larger than the amount set here.
amount | The minimum amount of data to be retained during a drain. |
unsigned long PIRL::Cache::data_margin | ( | ) | const [inline] |
Gets the size of the data margin that will be retained during a drain.
A generic data margin may be defined for any purpose. The required data amount for a data_test function is also a data margin. The effective data margin is the larger of the data margin set by the user, or the data amount (if any) required by the end-of-data test function minus one.
Referenced by drain().
Sets the end-of-data test function and the amount of data required for testing.
The tester function is a Data_Test type: it must take a single const char* argument, which will be the address of a valid user datum in the cache, and return a bool that is true when an end-of-data condition is encountered. The data_amount specifies the number of valid user data bytes that must be present starting at the data address passed to the tester function. N.B.: While the data address passed to the tester function is a char*, the data is not necessarily a C-string terminated with a zero-value character.
The tester function will be used during a refill to test the data acquired from the source. Testing starts with the next datum in the cache after the last one tested during the previous refill and continues to the datum at the required data amount distance from the end of user data. During a drain the remaining untested data is retained to ensure that it can be tested after more data is added after a refill. Note that if the tester function only examines the single datum at the address it is given (the data amount is 1) then no data will be retained when the cache is drained.
If the amount of data required by the tester function is greater than the cache capacity, then the capacity is increased to the data_amount.
tester | A Data_Test function. This may be NULL to disable end-of-data testing. |
data_amount | The amount of valid user data following the data address given to the tester function that must be present in the Cache. If this is 0 then tester will be set to NULL. |
Data_Test PIRL::Cache::data_test | ( | ) | const [inline] |
Gets the end-of-data test function.
unsigned long PIRL::Cache::data_test_amount | ( | ) | const [inline] |
Gets the amount of data required by the end-of-data test function.
void Cache::drain | ( | ) | [virtual] |
Drains the cache of consumed user data.
All user data from the start of the cache storage up to, but not including, the location of the next data pointer is defined as "consumed" and effectively removed from the cache. The remaining data is shifted to the start of the cache storage area, thus increasing the amount of free space for new user data to be added.
However, at least the amount of user data equal to the effective data margin is retained during a drain regardless of the location of the next data pointer. Therefore this amount at the end of the user data is always excluded from the consumed data.
The next data pointer is decremented by the amount of data consumed. The address in the cache storage where the user data ends (last) is also shifted.
References data_margin(), next(), and state_report().
bool Cache::refill | ( | unsigned long | max_amount = (unsigned long)-1 ) |
[virtual] |
Refills the cache from the data source stream.
If the amount of free data storage space is less than the max_amount to refill the cache it is first drained to maximize the amount of free space. Warning: If no free space can be made available then the cache is full and can not be refilled; it is not enlarged and the return value is true.
An attempt is made to fill the free space with data bytes read from the source stream. No more than max_amount of data will be read. The amount actually read may be less than the amount requested. The number of bytes read and the last user data pointer is updated by the amount read.
If no data is read and an end-of-file condition is encountered on the stream the return value will be false. N.B.: The stream may have an end-of-file status but the refill still return true if any data was read.
If an end-of-data test function has been provided, and the user data amount required by the function is present, then the new data is scanned by the function. The new data starts where the last scan left off: the pre-refill last margin datum (previous last() - data_test_amount()) plus 1 (previous margin datum was the last one scanned). The new data ends at the post-refill last margin datum (current last() - data_test_amount()). If the data test function returns true the datum that was passed to the function is considered to mark the logical end of user data. In this case an attempt is made reposition the input stream back to this location. If this fails (probably because the stream is not repositionable) an attempt is made to unget the data back onto the stream (a standard input stream can unget at least one byte). Failure to move a stream back sufficiently causes an overflow_error exception, with the Cache left in a state as if the extra bytes had not been read. A logical end-of-data condition will not affect any further operations on the Cache, but unless the stream is moved past the end-of-data position the next refill will encounter it again. A logical end-of-data condition will not result in a false return unless moving the stream position back resulted in effectively no data having been read.
max_amount | The maximum amount of data to read from the stream. |
std::ios::failure | If a source stream failure occurs. The cache pointers will still remain valid. |
overflow_error | If the stream could not be repositioned back to an end-of-data location. |
Cache & Cache::put | ( | char * | data, |
unsigned long | amount | ||
) | [virtual] |
Puts data into the cache storage.
The data is appended to any user data. If the amount_free is less than the amount of data to be added the cache is drained to maximize the amount of free space. If this is insufficient the cache capacity is enlarged to provided the needed space.
data | The address from which the user data is to be read. |
amount | The amount of data to put, in bytes. |
unsigned long Cache::get | ( | char * | data, |
unsigned long | amount | ||
) | [virtual] |
Gets data from the cache storage.
Data is copied out of cache storage starting at the next user data location. If the amount of user data to get is greater than the amount_remaining the cache will be refilled as needed to obtain more data.
data | The address where the user data is to be written. |
amount | The amount of data to get, in bytes. |
void Cache::reset | ( | ) | [virtual] |
Resets the cache to its empty state.
The number of bytes read is reset to zero.
Referenced by Cache().
unsigned long PIRL::Cache::capacity | ( | ) | const [inline] |
Gets the capacity of the data storage area.
N.B.: The capacity is the amount of allocated storage space allocated to the cache. This is not necessarily the same as the sum of amount_used and amount_free if the capacity has been set to an amount less than the allocated storage size.
Referenced by Cache().
Cache & Cache::capacity | ( | unsigned long | amount ) |
Sets the effective capacity of the data storage area.
The effective capacity is the maximum amount of the total storage capacity that will be used during a refill.
If the capacity amount is not being changed then nothing is done.
N.B.: If the amount is zero, then the presumptive capacity is the amount_used after a drain. If this is still zero then the storage area will be deallocated.
A non-zero amount will not be allowed to be less than a non-zero effective data margin plus one byte.
Setting a non-zero amount less than the current capacity will change the amount of space available for user data during a refill, but the amount of storage space allocated will not be changed. If the amount specified is less than the amount_used the cache will be drained.
When the capacity is being increased from its current storage amount the cache will first be drained. This will minimize the amount of data that needs to be copied to the new storage when the capacity is increased, and minimize potential loss of user data when the capacity is being increased. However, if the capacity is being reduced - which does not require storage reallocation and copying - and the new amount still has room for the current user data contents, the contents will not be drained.
amount | The effective capacity, in bytes, of the storage area. |
unsigned long PIRL::Cache::amount_used | ( | ) | const [inline] |
Gets the amount of cache storage in use.
unsigned long PIRL::Cache::amount_free | ( | ) | const [inline] |
Gets the amount of free cache space.
N.B.: The amount of free space does not necessarily include all of the remaining storage capacity. Rather, it is the amount available for use during a refill.
char* PIRL::Cache::start | ( | ) | const [inline] |
Gets the starting address of the cache data storage area.
Any user data will start at this address.
Cache& PIRL::Cache::next | ( | char * | location ) | [inline] |
Sets the location of the next user data.
All data before the next pointer is considered to be "consumed" by the user and will be logically removed from the cache when it is drained. However, the effective data margin will always be retained in the cache during a drain regardless of the location of the next pointer.
The next pointer provides the user with the means of logically moving in the cache to the next data location. The next pointer may be safely moved forward to any location, including locations beyond the last of the user data or the end of the cache storage. It may also be set back to a location before its current location, but will be constrained to an address that is greater than or equal to the start of the cache storage.
location | The new address of the next data pointer. |
char* PIRL::Cache::next | ( | ) | const [inline] |
Gets the address of the next user data.
N.B.: The next pointer will always be at or beyond the start of the cache storage area, however it may also be located beyond the last valid user datum or the end of the cache storage area.
Referenced by drain().
unsigned long PIRL::Cache::amount_consumed | ( | ) | const [inline] |
Gets the amount of user data used (consumed).
N.B.: Since the next user data pointer may be at any location beyond the start of the cache, it is possible to obtain a value that is greater than the amount_used or the capacity.
long PIRL::Cache::amount_remaining | ( | ) | const [inline] |
Gets how much more user data is available.
N.B.: Since the next user data pointer may be at any location beyond the start of the cache, it is possible to obtain a negative value.
char* PIRL::Cache::last | ( | ) | const [inline] |
Gets the address where the user data ends.
Cache & Cache::last | ( | char * | location ) |
Sets the location where the user data ends.
Caution: User data will be effectively deleted - if the new location is less than the current location - or generated (from remnant cache storage contents) - if the location is increased.
location | The address of the last (exclusive) user data in the storage area. |
void Cache::state_report | ( | std::ostream & | stream ) | const |
Generates a report on a stream of the current cache state.
stream | The ostream where the report will be written. |
void Cache::state_report | ( | ) | const |
Generates a report on stdout of the current cache state.
This is a convenience method that just passes cout to the state_report(std::ostream&) method.
Referenced by drain().
const char *const Cache::ID = "PIRL::Cache ($Revision: 1.10 $ $Date: 2010/11/11 20:41:40 $)" [static] |
Class identification name with source code version and date.