PIRL  PIRL++

Public Types | Public Member Functions | Static Public Attributes

PIRL::Cache Class Reference

A Cache is a dynamic input storage area. More...

#include <Cache.hh>

List of all members.

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.
Cachesource (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.
Cachedata_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.
Cachedata_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 Cacheput (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.
Cachecapacity (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.
Cachenext (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.
Cachelast (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.

Detailed Description

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.

Author:
Bradford Castalia, UA/PIRL
Revision:
1.8

Member Typedef Documentation

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.


Constructor & Destructor Documentation

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.

Parameters:
capacityThe capacity, in bytes, of the data storage area.
data_marginThe 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_testA Data_Test function that is used to test for an end-of-data condition during a refill of the cache contents.
See also:
data_test(Data_Test, unsigned long)
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.

Parameters:
capacityThe capacity, in bytes, of the data storage area.
sourceThe istream from which data will be obtained to refill the cache contents.
data_marginThe 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_testA Data_Test function that is used to test for an end-of-data condition during a refill of the cache contents.
See also:
data_test(Data_Test, unsigned long)
Cache::~Cache (  ) [virtual]

Destroys the Cache.

The data storage area is deleted.


Member Function Documentation

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.

Parameters:
sourceAn istream that will be used as the source of data when the cache is refilled.
Returns:
This Cache.
See also:
refill(unsigned long)

References source().

Referenced by source().

std::istream& PIRL::Cache::source (  ) const [inline]

Gets the data stream source.

Returns:
The istream
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.

Returns:
The total number of bytes read into the cache.
See also:
refill(unsigned long)
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.

Parameters:
amountThe minimum amount of data to be retained during a drain.
Returns:
This Cache.
See also:
drain()
data_margin()
data_test(Data_Test, unsigned long)
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.

Returns:
The effective data margin amount.
See also:
data_margin(unsigned long)
data_test(Data_Test, unsigned long)
drain()

Referenced by drain().

Cache & 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.

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.

Parameters:
testerA Data_Test function. This may be NULL to disable end-of-data testing.
data_amountThe 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.
Returns:
This Cache.
See also:
data_margin(unsigned long)
refill(unsigned long)
Data_Test PIRL::Cache::data_test (  ) const [inline]

Gets the end-of-data test function.

Returns:
A pointer to the end-of-data test function. This will be NULL if there is no test function.
See also:
data_test(Data_Test, unsgined long)
unsigned long PIRL::Cache::data_test_amount (  ) const [inline]

Gets the amount of data required by the end-of-data test function.

Returns:
The amount of data, in bytes, required by the 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.

See also:
next(char*)

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.

Parameters:
max_amountThe maximum amount of data to read from the stream.
Returns:
false if the stream end-of-file or logical end-of-data was encounterd; true otherwise. If the cache has no capacity false is always returned.
Exceptions:
std::ios::failureIf a source stream failure occurs. The cache pointers will still remain valid.
overflow_errorIf the stream could not be repositioned back to an end-of-data location.
See also:
drain()
data_test(Data_Test, unsigned long)
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.

Parameters:
dataThe address from which the user data is to be read.
amountThe amount of data to put, in bytes.
Returns:
This Cache.
See also:
last()
amount_free()
drain()
capacity(unsigned long)
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.

Parameters:
dataThe address where the user data is to be written.
amountThe amount of data to get, in bytes.
Returns:
The amount of data that was copied to the data address. The only time this will be less than the amount requested is if the end-of-data has been reached.
See also:
next()
amount_remaining()
data_test (Data_Test, unsigned long)
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.

Returns:
The number of bytes allocated to data storage.
See also:
capacity(unsigned long)

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.

Parameters:
amountThe effective capacity, in bytes, of the storage area.
Returns:
This Cache.
See also:
drain()
amount_used()
unsigned long PIRL::Cache::amount_used (  ) const [inline]

Gets the amount of cache storage in use.

Returns:
The amount, in bytes, of storage occupied by user data.
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.

Returns:
The amount, in bytes, of storage not occupied by user data that is available for use by 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.

Returns:
The start address of the cache storage area. N.B.: This will be NULL if the cache has no data storage.
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.

Parameters:
locationThe new address of the next data pointer.
Returns:
This Cache.
See also:
drain()
data_margin()
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.

Returns:
A pointer to the next user data location. N.B.: This will be NULL if the cache has no data storage.

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.

Returns:
The distance, in bytes, from the start of the cache to the next user data.
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.

Returns:
The distance, in bytes, from the next user datum to the end (last) of user data.
char* PIRL::Cache::last (  ) const [inline]

Gets the address where the user data ends.

Returns:
A pointer to the byte following the last user datum in the cache. N.B.: This will be NULL if the cache has no data storage.
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.

Parameters:
locationThe address of the last (exclusive) user data in the storage area.
Returns:
This Cache.
void Cache::state_report ( std::ostream &  stream ) const

Generates a report on a stream of the current cache state.

Parameters:
streamThe 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.

See also:
state_report(std::ostream&)

Referenced by drain().


Member Data Documentation

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.


The documentation for this class was generated from the following files: