JX Application Framework
|
#include <JFileArray.h>
Classes | |
class | FileAlreadyOpen |
class | FileNotWritable |
class | ItemChanged |
class | ItemInserted |
class | ItemMoved |
class | ItemRemoved |
class | ItemsSwapped |
class | NotEmbeddedFile |
class | WrongSignature |
Public Types | |
enum | CreateAction { kFailIfOpen , kIgnoreIfOpen , kDeleteIfOpen , kTryWaitUntilCanOpen , kDeleteIfWaitTimeout } |
enum | { kUnsignedLongLength = 4 } |
Public Member Functions | |
~JFileArray () override | |
const JString & | GetFileName () const |
JFileVersion | GetVersion () const |
void | SetVersion (const JFileVersion newVersion) |
void | GetItem (const JFAIndex &index, std::string *data) const |
void | GetItem (const JFAID &id, std::string *data) const |
void | SetItem (const JFAIndex &index, const JString &data) |
void | SetItem (const JFAID &id, const JString &data) |
void | InsertItemAtIndex (const JFAIndex &index, const JString &data) |
void | PrependItem (const JString &data) |
void | AppendItem (const JString &data) |
void | SetItem (const JFAIndex &index, std::ostringstream &dataStream) |
void | SetItem (const JFAID &id, std::ostringstream &dataStream) |
void | InsertItemAtIndex (const JFAIndex &index, std::ostringstream &dataStream) |
void | PrependItem (std::ostringstream &dataStream) |
void | AppendItem (std::ostringstream &dataStream) |
void | RemoveItem (const JFAIndex &index) |
void | RemoveItem (const JFAID &id) |
void | MoveItemToIndex (const JFAIndex ¤tIndex, const JFAIndex &newIndex) |
void | SwapItems (const JFAIndex &index1, const JFAIndex &index2) |
bool | IndexToID (const JFAIndex &index, JFAID *id) const |
bool | IDToIndex (const JFAID &id, JFAIndex *index) const |
bool | IndexValid (const JFAIndex &index) const |
bool | IDValid (const JFAID &id) const |
bool | WillFlushChanges () const |
void | ShouldFlushChanges (const bool write) |
void | FlushChanges () |
![]() | |
JCollection () | |
JCollection (const JCollection &source) | |
~JCollection () override | |
JCollection & | operator= (const JCollection &source) |
JSize | GetItemCount () const |
bool | IsEmpty () const |
bool | IndexValid (const JIndex index) const |
JIndex | GetIndexFromEnd (const JIndex index) const |
JString | ToString () const override |
![]() | |
JBroadcaster () | |
virtual | ~JBroadcaster () |
JBroadcaster & | operator= (const JBroadcaster &source) |
bool | HasSenders () const |
JSize | GetSenderCount () const |
bool | HasRecipients () const |
JSize | GetRecipientCount () const |
template<class T > | |
void | ListenTo (const JBroadcaster *sender, const std::function< void(const T &)> &f) |
Static Public Member Functions | |
static JError | Create (const JString &fileName, const JUtf8Byte *fileSignature, JFileArray **obj, const CreateAction action=kFailIfOpen) |
static JError | OKToCreateBase (const JString &fileName, const JUtf8Byte *fileSignature, const CreateAction action=kFailIfOpen) |
static JError | Create (JFileArray *theEnclosingFile, const JFAID &enclosureItemID, JFileArray **obj) |
static JError | OKToCreateEmbedded (JFileArray *theEnclosingFile, const JFAID &enclosureItemID) |
Static Public Attributes | |
static const JFileVersion | kInitialVersion = 0 |
static const JUtf8Byte * | kItemInserted = "ItemInserted::JFileArray" |
static const JUtf8Byte * | kItemRemoved = "ItemRemoved::JFileArray" |
static const JUtf8Byte * | kItemMoved = "ItemMoved::JFileArray" |
static const JUtf8Byte * | kItemsSwapped = "ItemsSwapped::JFileArray" |
static const JUtf8Byte * | kItemChanged = "ItemChanged::JFileArray" |
static const JUtf8Byte * | kFileNotWritable = "FileNotWritable::JFileArray" |
static const JUtf8Byte * | kFileAlreadyOpen = "FileAlreadyOpen::JFileArray" |
static const JUtf8Byte * | kWrongSignature = "WrongSignature::JFileArray" |
static const JUtf8Byte * | kNotEmbeddedFile = "NotEmbeddedFile::JFileArray" |
Protected Member Functions | |
JFileArray (const JString &fileName, const JUtf8Byte *fileSignature, const CreateAction action) | |
JFileArray (JFileArray *theEnclosingFile, const JFAID &enclosureItemID) | |
JFileArrayIndex * | GetFileArrayIndex () |
![]() | |
void | ItemAdded () |
void | ItemRemoved () |
void | SetItemCount (const JSize newItemCount) |
![]() | |
JBroadcaster (const JBroadcaster &source) | |
void | ListenTo (const JBroadcaster *sender) |
void | StopListening (const JBroadcaster *sender) |
void | ClearWhenGoingAway (const JBroadcaster *sender, void *pointerToMember) |
void | StopListening (const JBroadcaster *sender, const std::type_info &messageType) |
template<class T > | |
void | Send (JBroadcaster *recipient, const T &message) |
template<class T > | |
void | Broadcast (const T &message) |
virtual void | Receive (JBroadcaster *sender, const Message &message) |
void | SendWithFeedback (JBroadcaster *recipient, Message *message) |
void | BroadcastWithFeedback (Message *message) |
virtual void | ReceiveWithFeedback (JBroadcaster *sender, Message *message) |
virtual void | ReceiveGoingAway (JBroadcaster *sender) |
Friends | |
class | JFileArrayIndex |
The Array-in-a-File Class An array implemented as a file. All data is stored as text and is transferred via stringstream objects. Each item can have an arbitrary size. A JFileArray can be embedded within other JFileArray by storing all the embedded file's data inside one item of the enclosing file. The single base file object is initialized with the file specifications. An embedded file object is initialized with the file object that contains it and the ID of the item that contains it. The embedding can theoretically go on forever. In practice, deep embedding can be hard to keep track of. Embedded files must be opened after the base file and must be closed before the base file. Storage details: The first item is the file signature (arbitrary length). The second item is the version. The third item is the number of items in the array. The fourth item is the offset into the file where the index starts. Each item is preceded by its length. (This makes it easier to recover the data directly from the file.) The positions and id's of the items in the file are stored at the end of the file. This is handled by JFileArrayIndex. Since both the data and index sections have to change size, the index was placed at the end because it is usually significantly smaller and only needs to be written out when the file is closed. sig header items (length+data) index +--+--+--+--+-------------------------------+-------------------+ | | | | | ++---++---+- - - -++---++---+ +-+-+- - - -+-+-+ | | | | | || || | || || | | | | | | | | | | | | || || | || || | | | | | | | | | | | | ++---++---+- - - -++---++---+ +-+-+- - - -+-+-+ +--+--+--+--+-------------------------------+-------------------+ Implementation details: Only the base file opens the stream. All embedded files simply get a pointer to the stream so they can use it. This means that one should never rely on the position of the read or write mark unless the previous statement explicitly set it. Embedded files should not delete itsStream. The file's header and index are read in when the file is opened and is maintained in memory. However, the header and index are also written to the file whenever they change. This provides safety in the event of program and system crashes. It also slows the program down, however. One could use a flag to tell whether to always update the file or just update it when it is closed. While the file is open, do not rely on the data in the header or index sections of the file. Use the data members and itsFileIndex. The information in the space allocated for the header and index is undefined. While the file is open, space for the index is still maintained at the end of the file to avoid having to adjust the allocation when the index is written out. Since some information is only written out when the file is closed, only one process at a time can open the disk file. To guarantee this, the high bit of the itemCount is set when the file is opened. This does not conflict with other uses because one will run out of RAM and disk space long before one needs the high bit in itemCount. (If you're not out of space, switch to a real database system!) If this bit is set, JFileArray::Create() will return false.
|
override |
All embedded files must be closed before calling this!
We could use a Message to notify the owners of embedded files that the files have been closed, but it is much easier and safer to simply write client code that closes the embedded files first.
|
protected |
Initialize a JFileArray object as the base file. Since we are the base class, we create and open the std::fstream.
|
protected |
Initialize a JFileArray object as a nested part of the given JFileArray.
|
inline |
|
inline |
|
static |
By forcing everyone to use this function, we avoid having to worry about errors within the class itself.
Derived classes must define their own constructor functions and check OKToCreateBase() before creating the object.
Be very careful when using kIgnoreIfOpen. If you always call ShouldFlushChanges(true) when you open the file, it should be safe to specify kIgnoreIfOpen, but only if JFileArray itself did not cause the crash.
kTryWaitUntilCanOpen does not guarantee that Create() will return true. If somebody else never closes the file, Create() will fail. This is safer than blocking forever.
The code for kTryWaitUntilCanOpen and kDeleteIfWaitTimeout suffers from a race condition. If it ever becomes a problem, it will need to use lockfile instead.
|
static |
By forcing everyone to use this function, we avoid having to worry about errors within the class itself.
Derived classes must define their own constructor functions and check OKToCreateEmbedded() before creating the object.
void JFileArray::FlushChanges | ( | ) |
Write out the header information and the file's index.
This is called automatically if ShouldFlushChanges(true) was called. You can optimize by calling ShouldFlushChanges(false) and then calling FlushChanges() after making a sequence of changes.
|
inlineprotected |
const JString & JFileArray::GetFileName | ( | ) | const |
Returns the name of the file on disk.
void JFileArray::GetItem | ( | const JFAID & | id, |
std::string * | data | ||
) | const |
void JFileArray::GetItem | ( | const JFAIndex & | index, |
std::string * | data | ||
) | const |
Fills the given string with a copy of the data for the specified item.
|
inline |
Return the index of the item with the specified ID. Returns an invalid JFAIndex if there is no item with the specified ID.
This is not inline because JFileArrayIndex is forward declared.
Return the ID of the specified item.
This is not inline because JFileArrayIndex is forward declared.
void JFileArray::InsertItemAtIndex | ( | const JFAIndex & | index, |
std::ostringstream & | dataStream | ||
) |
Insert an item into the array at the specified index.
If index is any value greater than the current number of items, then the item is appended to the end of the array.
The actual data is appended to the data section of the file. The index entry for the item is inserted into the file's index at the specified index.
Move the specified item to a different index in the file.
|
static |
|
static |
|
inline |
|
inline |
void JFileArray::RemoveItem | ( | const JFAID & | id | ) |
void JFileArray::RemoveItem | ( | const JFAIndex & | index | ) |
Remove the specified item from the file.
If it is an embedded file, it must already be closed.
void JFileArray::SetItem | ( | const JFAID & | id, |
std::ostringstream & | dataStream | ||
) |
void JFileArray::SetItem | ( | const JFAIndex & | index, |
std::ostringstream & | dataStream | ||
) |
Write out the contents of the ostringstream to the specified item.
|
inline |
|
inline |
Interchange the specified items in the file.
|
inline |
When this flag is set, the file's index will be written out after every change. The default is not to do this, since it slows us down dramatically. If you need to protect against data loss due to crashes, you should turn this option on.
|
friend |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |