ztd/include/filedat.hpp
2020-02-20 11:37:11 +01:00

430 lines
15 KiB
C++

#ifndef FILEDAT_HPP
#define FILEDAT_HPP
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <fstream>
#include <exception>
#include <cstring>
/*! @file filedat.hpp
* @brief Storing and reading data
*
* Easily organize data in a JSON-like file format.
* See [ZFD format](@ref zfd)
*/
namespace ztd
{
class filedat;
class chunkdat;
class format_error;
//! @brief Abstract data storing object
/*! Used for inheritance and type classing.
<b> Not for external use </b>
*/
class chunk_abstract
{
public:
//! @brief Type of data
/*! Values: none , string , map , list
*/
enum typeEnum { none, string, map, list};
//! @brief Get type of chunk
typeEnum type();
chunk_abstract();
virtual ~chunk_abstract();
protected:
typeEnum m_type;
};
//! @brief String data storing class
/*!
Back-end of string data chunk.
<b> Not for external use </b>
*/
class chunk_string : public chunk_abstract
{
public:
//! @brief String data
std::string val;
chunk_string();
virtual ~chunk_string();
};
//! @brief Map data storing class
/*!
Back-end of map data chunk.
<b> Not for external use </b>
*/
class chunk_map : public chunk_abstract
{
public:
//! @brief Mapped data
std::map<std::string, chunkdat*> values;
chunk_map();
virtual ~chunk_map();
};
//! @brief String data storing class
/*!
Back-end of list data chunk.
<b> Not for external use </b>
*/
class chunk_list : public chunk_abstract
{
public:
//! @brief List data
std::vector<chunkdat*> list;
chunk_list();
virtual ~chunk_list();
};
//! @brief Chunk data object
/*!
Object containing a chunk of data\n
Either string, map, or list
*/
class chunkdat
{
public:
//! @brief Constructor
chunkdat();
//! @brief Constructor with initial value
chunkdat(const char* in);
//! @brief Constructor with initial value
chunkdat(std::string const& in);
chunkdat(const char* in, const int in_size, int offset=0, filedat* data=nullptr);
//! @brief Constructor with copy
chunkdat(chunkdat const& in);
//dtor
~chunkdat();
//! @brief Clear contents
void clear();
//! @brief Type of the stored data
chunk_abstract::typeEnum type() const;
//! @brief get pointer to chunk_abstract
inline chunk_abstract* getp() const { return m_achunk; }
//! @brief Size of list. -1 if not a list
int listSize() const;
//! @brief Get pointer to parent (debug)
inline filedat* parent() const { return m_parent; }
//! @brief Get data offset (debug)
inline int offset() const { return m_offset; }
//! @brief Set data
/*!
@param in C string data
@param in_size Size of the string data
@param offset Used for debugging
@param parent Used for debugging
*/
void set(const char* in, const int in_size, int offset=0, filedat* parent=nullptr);
//! @brief Set data
/*!
@param in String data
@param offset Used for debugging
@param data Used for debugging
*/
inline void set(std::string const& in, int offset=0, filedat* data=nullptr) { this->set(in.c_str(), in.size(), offset, data); }
//! @brief Copy chunk's data
inline void set(chunkdat const& in) { this->set(in.strval(), in.offset(), in.parent()); } // TODO
//! @brief Get string value of data
/*!
@param alignment Number of initial aligners
@param aligner String to use for aligning sub-chunks
@return String value of the whole chunk data
*/
std::string strval(unsigned int alignment=0, std::string const& aligner="\t") const;
//! @brief alias for strval()
inline std::string str(unsigned int alignment=0, std::string const& aligner="\t") const { return strval(alignment, aligner); }
void addToMap(std::string const& name, chunkdat const& val);
void addToMap(std::vector<std::pair<std::string, chunkdat>> const& vec);
void addToList(chunkdat const& val);
void addToList(std::vector<chunkdat> const& vec);
//! @brief Add keyed data to map chunk
/*!
@param name Key of the data
@param val Data
*/
inline void add(std::string const& name, chunkdat const& val) { addToMap(name, val); }
//! @brief Add multiple keyed data to map chunk
/*!
@param vec Vector of pairs of keys and data
*/
inline void add(std::vector<std::pair<std::string, chunkdat>> const& vec) { addToMap(vec); }
//! @brief Append data to end of list
/*!
@param val Data to add
*/
inline void add(chunkdat const& val) { addToList(val); }
//! @brief Append list of data to end of list
/*!
@param vec Vector of data to add
*/
inline void add(std::vector<chunkdat> const& vec) { addToList(vec); }
//! @brief Concatenate chunks of data
/*! Effective only if the two chunks are of the same type\n
Map: combines two maps into a single map\n
List: combines into a single list\n
String: Concatenate strings
*/
void concatenate(chunkdat const& chk);
void erase(const std::string& key);
void erase(const unsigned int index);
//! @brief Create a copy of the chunk
inline chunkdat copy() const { return chunkdat(*this); }
//! @brief Create a pointed copy of the chunk
inline chunkdat* pcopy() const { return new chunkdat(*this); }
//! @brief Reference to subchunk of map
/*!
Throws format_error exception when operation fails
@param a Key of the subchunk data
@return Reference to the subchunk in question
*/
chunkdat& subChunkRef(std::string const& a) const;
//! @brief Reference to subchunk of list
/*!
Throws format_error exception when operation fails
@param a Position of subchunk data in list
@return Reference to the subchunk in question
*/
chunkdat& subChunkRef(const unsigned int a) const;
//! @brief Pointer to subchunk of map
/*!
@param a Key of the subchunk data
@return Reference to the subchunk in question\n
nullptr if operation failed
*/
chunkdat* subChunkPtr(std::string const& a) const;
//! @brief Pointer to subchunk of list
/*!
@param a Position of subchunk data in list
@return Reference to the subchunk in question\n
nullptr if operation failed
*/
chunkdat* subChunkPtr(const unsigned int a) const;
//! @brief Reference to subchunk of map. @see subChunkRef(std::string const& a) const
inline chunkdat& operator[](std::string const& a) const { return subChunkRef(a); }
//! @brief Reference to subchunk of list. @see subChunkRef(const unsigned int a) const
inline chunkdat& operator[](const unsigned int a) const { return subChunkRef(a); }
//! @brief Set chunk data and return *this. @see set(chunkdat const& in)
inline chunkdat& operator=(chunkdat const& a) { set(a); return *this; }
//! @brief add() and return *this. @see add(std::string const& name, chunkdat const& val)
inline chunkdat& operator+=(std::pair<std::string, chunkdat> const& a) { add(a.first, a.second); return *this; }
//! @brief add() and return *this. @see add(std::vector<std::pair<std::string, chunkdat>> const& vec)
inline chunkdat& operator+=(std::vector<std::pair<std::string, chunkdat>> const& a) { add(a); return *this; }
//! @brief add() and return *this. @see add(chunkdat const& val)
inline chunkdat& operator+=(chunkdat const& a) { add(a); return *this; }
//! @brief add() and return *this. @see add(std::vector<chunkdat> const& vec)
inline chunkdat& operator+=(std::vector<chunkdat> const& a) { add(a); return *this; }
//! @brief concatenate and return *this. @see concatenate(chunkdat const& chk)
inline chunkdat& operator*=(chunkdat const& a) { concatenate(a); return *this; }
//! @brief erase() and return *this. @see remove(const std::string& key)
inline chunkdat& operator-=(const std::string& key) { erase(key); return *this; }
//! @brief erase() and return *this. @see remove(const unsigned int index)
inline chunkdat& operator-=(const unsigned int index) { erase(index); return *this; }
//add operator+ and operator*
//! @brief give strval
inline operator std::string() const { return this->strval(); }
// inline operator const char*() const { return this->strval().c_str(); }
protected:
filedat* m_parent;
int m_offset;
chunk_abstract* m_achunk;
};
inline bool operator==(const chunkdat& a, const char* b) { return a.strval() == b; }
//! @brief add
inline chunkdat operator+(const chunkdat& a, const std::pair<std::string, chunkdat>& b) { chunkdat ret(a); ret += b; return ret; }
//! @brief add
inline chunkdat operator+(const chunkdat& a, const std::vector<std::pair<std::string, chunkdat>>& b) { chunkdat ret(a); ret += b; return ret; }
//! @brief add
inline chunkdat operator+(const chunkdat& a, const chunkdat& b) { chunkdat ret(a); ret += b; return ret; }
//! @brief add
inline chunkdat operator+(const chunkdat& a, const std::vector<chunkdat>& b) { chunkdat ret(a); ret += b; return ret; }
//! @brief concatenated chunk
inline chunkdat operator*(const chunkdat& a, const chunkdat& b) { chunkdat ret(a); ret *= b; return ret; }
//! @brief substract
inline chunkdat operator-(const chunkdat& a, const std::string& b) { chunkdat ret(a); ret -= b; return ret; }
//! @brief substract
inline chunkdat operator-(const chunkdat& a, const unsigned int b) { chunkdat ret(a); ret -= b; return ret; }
//! @brief File data object
/*!
Object for importing, reading, altering and writing of file data\n
*/
class filedat
{
public:
//! @brief Constructor
filedat();
//! @brief Constructor with initial file path
filedat(std::string const& in);
virtual ~filedat();
//! @brief Get current file path
inline std::string filePath() const { return m_filePath; }
//! @brief Set file path
inline void setFilePath(std::string const& in) { m_filePath=in; }
//! @brief Test wether file can be read
bool readTest() const;
//! @brief Import file data
/*!
Throws format_error exceptions if errors are encountered while reading
@param path Will set this as file path if not empty
*/
void import_file(const std::string& path="");
//! @brief Import data from stdin
/*!
Throws format_error exceptions if errors are encountered while reading
*/
void import_stdin();
//! @brief Import data from string
/*!
Throws format_error exceptions if errors are encountered while reading
*/
void import_string(const std::string& data);
//! @brief Export data to file
/*!
@param path Will set this as file path if not empty
@param aligner String used to align subchunks
*/
bool export_file(std::string const& path="", std::string const& aligner="\t") const;
//! @brief Clear contents of data
void clear();
//! @brief Get string value of data
/*!
@param aligner String used to align subchunks
*/
std::string strval(std::string const& aligner="\t") const;
//! @brief Get reference to chunk data
inline chunkdat& data() const { return *m_dataChunk; }
//! @brief Get pointer to chunk data
inline chunkdat* pdata() const { return m_dataChunk; }
//! @brief Set data
/*!
Throws format_error exceptions if errors are encountered
@see chunkdat::set(chunkdat const& a)
*/
inline void set_data(chunkdat const& in) { m_dataChunk->set(in); }
//! @brief Imported data as is. Used for debugging
inline const std::string& im_data() const { return m_data; }
//! @brief Imported data as is. Used for debugging
inline const char* im_c_data() const { return m_data.c_str(); }
//! @brief Reference to subchunk
//! @see chunkdat::operator[](std::string const &a) const
inline chunkdat& operator[](const std::string& index) const { return m_dataChunk->subChunkRef(index); }
//! @brief Reference to subchunk
//! @see chunkdat::operator[](const unsigned int a) const
inline chunkdat& operator[](const unsigned int index) const { return m_dataChunk->subChunkRef(index); }
//! @brief add data and return *this
//! @see chunkdat::operator+=(std::pair<std::string, chunkdat> const& a)
inline filedat& operator+=(std::pair<std::string, chunkdat> const& a) { *m_dataChunk += a; return *this; }
//! @brief add data and return *this
//! @see chunkdat::operator+=(std::vector<std::pair<std::string, chunkdat>> const& a)
inline filedat& operator+=(std::vector<std::pair<std::string, chunkdat>> const& a) { *m_dataChunk += a; return *this; }
//! @brief add data and return *this
//! @see chunkdat::operator+=(chunkdat const& a)
inline filedat& operator+=(chunkdat const& a) { *m_dataChunk += a; return *this; }
//! @brief add() and return *this
//! @see chunkdat::operator+=(std::vector<chunkdat> const& a)
inline filedat& operator+=(std::vector<chunkdat> const& a) { *m_dataChunk += a; return *this; }
//! @brief set_data() and return *this
//! @see chunkdat::operator+=(std::vector<chunkdat> const& a)
inline filedat& operator=(chunkdat const& a) { set_data(a); return *this; }
//! @brief Is a read char
static bool isRead(char in);
inline operator chunkdat() const { return *m_dataChunk; }
// inline operator std::string() const { if(m_dataChunk!=nullptr) return m_dataChunk->strval(); else return ""; }
private:
//functions
void generateChunk();
//attributes
std::string m_filePath;
std::string m_data;
chunkdat* m_dataChunk;
};
//! @brief Data format exception
/*!
Thrown when errors are encountered when manipulating data chunks
*/
class format_error : public std::exception
{
public:
//! @brief Conctructor
inline format_error(const std::string& what, const std::string& origin, const std::string& data, int where) { desc=what; index=where; filename=origin; sdat=data; }
//! @brief Error message
inline const char * what () const throw () {return desc.c_str();}
//! @brief Origin of the data, name of imported file, otherwise empty if generated
inline const char * origin() const throw () {return filename.c_str();}
//! @brief Data causing the exception
inline const char * data() const throw () {return sdat.c_str();}
//! @brief Where the error is located in the data
inline const int where () const throw () {return index;}
private:
std::string desc;
int index;
std::string filename;
std::string sdat;
};
inline std::ostream& operator<<(std::ostream& stream, chunkdat const& a) { return stream << a.strval(); }
inline std::ostream& operator<<(std::ostream& stream, filedat const& a) { return stream << a.strval(); }
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin);
//! @brief Print exception to console
/*!
If origin is known, displays location and discriminating line\n
If origin is unknown, displays whole data up to discriminating line
*/
void printFormatException(format_error& exc);
}
#endif //FILEDAT_HPP