- Brief description
- Including headers in an executable
- Creating a shared library with the Union class
- Description of types and methods
The class provides a simple interface for combining several basic types into a single union.
An fcf::Union object can store one of the following types:
fcf::Undefined (Numerical equivalent: fcf::UT_UNDEFINED),
fcf::Null (Numerical equivalent: fcf::UT_NULL),
int (Numerical equivalent: fcf::UT_INT),
unsigned int (Numerical equivalent: fcf::UT_UINT),
long long (Numerical equivalent: fcf::UT_LONGLONG),
unsigned long long (Numerical equivalent: fcf::UT_ULONGLONG),
double (Numerical equivalent: fcf::UT_DOUBLE),
bool (Numerical equivalent: fcf::UT_BOOL),
std::string (Numerical equivalent: fcf::UT_STRING),
fcf::UnionVector /*std::vector<fcf::Union>*/ (Numerical equivalent: fcf::UT_VECTOR),
fcf::UnionMap /*std::map<fcf::Union, fcf::Union, fcf::UnionMapLess>*/ (Numerical equivalent: fcf::UT_MAP),
The library is distributed in the form of header files and to start using it, you need to declare the implementation in one cpp file. This is done by including the union.hpp file with the declared FCF_UNION_IMPLEMENTATION
macro, in other files with the included union.hpp, the FCF_UNION_IMPLEMENTATION
macro is not needed
#define FCF_UNION_IMPLEMENTATION
#include <fcfUnion/union.hpp>
#include <iostream>
#include <sstream>
int main(int a_argc, const char* a_argv[]){
//----------------------------
// Example of a simple conversion
//----------------------------
fcf::Union uDoubleValue(3.14);
double dDoubleValue = (double)uDoubleValue;
int iDoubleValue = (int)uDoubleValue;
std::string sDoubleValue = (std::string)uDoubleValue;
//
// Result
// StdOut: Union value: 3.140000; doubel value: 3.14; int value: 3; std::string: 3.140000
//
std::cout << "Union value: " << uDoubleValue
<< "; doubel value: " << dDoubleValue
<< "; int value: " << iDoubleValue
<< "; std::string: " << sDoubleValue << std::endl;
//----------------------------
// Example of JSON output
//----------------------------
fcf::Union uMap(fcf::UT_MAP);
uMap["key1"] = "value1";
uMap["key2"] = fcf::Union(fcf::UT_VECTOR);
uMap["key2"].insert(1);
uMap["key2"].insert(2);
uMap["key2"].insert(3);
uMap["key3"] = "value3";
fcf::UnionStringifyOptions so;
so.friendly = true;
so.tab = " ";
std::stringstream ss;
uMap.stringify(ss, so);
//
// Result
// StdOut: JSON for map value:
// StdOut: {
// StdOut: "key1": "value1",
// StdOut: "key2": [1, 2, 3],
// StdOut: "key3": "value3"
// StdOut: }
std::cout << std::endl;
std::cout << "JSON for map value: \n" << ss.str() << std::endl;
//----------------------------
// JSON/JSObject parsing example
//----------------------------
std::stringstream ssource(
"{\n"
" // First value\n"
" 1: \"value1\", \n"
"\n"
" /* The second value in the sequence */ \n"
" key9: \"value9\", \n"
"\n"
" \"key3\": [1,2,3], \n"
"}"
);
fcf::Union uJson;
uJson.parse(ssource);
//
// Result
// StdOut: The object obtained from JSON is a map: 1
// StdOut: The object contains 3 values:
// StdOut: [1]: value1
// StdOut: [key9]: value9
// StdOut: [key3]: [1, 2, 3]
// StdOut:
// StdOut: First value from object 'key3': 1
// StdOut: The 'key3' object contains 3 values:
// StdOut: [0]: 1
// StdOut: [1]: 2
// StdOut: [2]: 3
std::cout << std::endl;
std::cout << "The object obtained from JSON is a map: " << uJson.is<fcf::UnionMap>() << std::endl;
std::cout << "The object contains " << uJson.size() << " values:" << std::endl;
// We use iteration with preservation of the original order (obegin/oend)
for(fcf::Union::iterator it = uJson.obegin(); it != uJson.oend(); ++it) {
std::cout << " [" << it.key() << "]: " << it.value() << std::endl;
}
// Access to vector elements is similar
std::cout << std::endl;
std::cout << " First value from object 'key3': " << uJson["key3"][0] << std::endl;
std::cout << " The 'key3' object contains " << uJson["key3"].size() << " values:" << std::endl;
for(fcf::Union::iterator it = uJson["key3"].begin(); it != uJson["key3"].end(); ++it) {
std::cout << " [" << it.key() << "]: " << it.value() << std::endl;
}
return 0;
}
As mentioned earlier, to include union.hpp it is necessary to declare the implementation (Include the union.hpp file with the declared FCF_UNION_IMPLEMENTATION
macro). It is best to use a separate file for this, for example unionImpl.cpp. This will allow you to avoid recompiling union.hpp when editing the project. This approach is given as an example below:
unionImpl.cpp file:
#define FCF_UNION_IMPLEMENTATION
#include <fcfUnion/union.hpp>
main.cpp file:
#include <fcfUnion/union.hpp>
#include <iostream>
#include <fstream>
int main(int a_argc, char* a_argv[]){
const char* confFilePath = "../test/config.json";
std::ifstream ifs;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
ifs.open(confFilePath);
ifs.exceptions(std::ifstream::badbit);
} catch(std::exception& e){
std::cout << "ERROR: Failed open file '" << confFilePath << "'." << std::endl;
return 1;
}
fcf::Union u;
u.parse(ifs);
// Result
// StdOut: The file contains a JSON object: 1
// StdOut: Fields:
// StdOut: [param1]: some value
std::cout << "The file contains a JSON object: " << u.is<fcf::UnionMap>() << std::endl;
std::cout << " Fields: " << std::endl;
std::cout << " [param1]: " << u["param1"] << std::endl;
return 0;
}
CMakeLists.txt file
cmake_minimum_required(VERSION 3.0)
project(example002)
include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/../../../)
add_executable(exemple002 unionImpl.cpp main.cpp)
You can also create a shared DLL/SO that exports the fcf::Union
class.
- To do this, the shared library project must declare the macro
FCF_UNION_EXPORT
- The library must declare an implementation of
fcf::Union
(The header union.hpp with the declared macroFCF_UNION_IMPLEMENTATION
must be included). - In each project in which the library is connected, the macro FCF_UNION_IMPORT must be declared.
Below is a simple example of exporting and importing the fcf::Union class.
executable/main.cpp file
#include <fcfUnion/union.hpp>
#include <iostream>
#include <fstream>
int main(int a_argc, char* a_argv[]){
std::ifstream ifs("config.json");
fcf::Union u;
u.parse(ifs);
std::cout << " The file contains a JSON object: " << u.is<fcf::UnionMap>() << std::endl;
std::cout << " Fields: " << std::endl;
std::cout << " [param1]: " << u["param1"] << std::endl;
return 0;
}
library/unionImpl.cpp file
#define FCF_IMPLEMENTATION
#include <fcfUnion/union.hpp>
CMakeLists.txt file
In the project parameters, we declare the macros FCF_UNION_IMPORT
and FCF_UNION_EXPORT
cmake_minimum_required(VERSION 3.0)
project(example003)
include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/../../../)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
file(COPY ../config.json DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
add_library("example003l" SHARED ./library/unionImpl.cpp)
# Declare the FCF_UNION_EXPORT macro for the shared library
target_compile_definitions(example003l PRIVATE FCF_UNION_EXPORT)
add_executable(example003 ./executable/main.cpp)
# Declare the FCF_UNION_IMPORT macro for the executable
target_compile_definitions(example003 PRIVATE FCF_UNION_IMPORT)
target_link_libraries(example003 PRIVATE "example003l")
Enum of integer type identifiers stored by the fcf::Union
class
UT_UNDEFINED
-fcf::Undefined
typeUT_NULL
-fcf::Null
typeUT_INT
-int
typeUT_UINT
-unsigned int
typeUT_LONGLONG
-long long
typeUT_ULONGLONG
-unsigned long long
typeUT_DOUBLE
-double
typeUT_BOOL
-bool
typeUT_STRING
-std::string
typeUT_VECTOR
-fcf::UnionVector
type (std::vector<fcf::Union>
)UT_MAP
- -fcf::UnionMap
type (std::map<fcf::Union, fcf::Union, fcf::UnionMapLess>
),
Structure describing the parameters of translation into string format/JSON
bool friendly = false
- Iftrue
, then output is generated with line breaks and indentation.const char* tab = " "
- A line containing a tab.fcf::UnionFormat mode = SF_JSON
- Output format. SF_JSON - Json format. SF_VALUE - the value format is similar to SF_JSON, if the root element is a string, then the value will not be enclosed in quotation marks when output.
Class of iterator of children of the object fcf::Union
Union key() const
- Child element name/keyUnion* operator->()
- Gets a pointer to the child elementUnion& operator()
- Gets a reference to a child elementUnion& value()
- Gets a reference to a child elementbase_iterator& operator++()
- incrementbool operator==(const base_iterator& a_it) const
- comparisonbool operator!=(const base_iterator& a_it) const
- comparison
Class of const iterator of children of the object fcf::Union
Union key() const
- Child element name/keyconst Union* operator->()
- Gets a pointer to the child elementconst Union& operator()
- Gets a reference to a child elementconst Union& value()
- Gets a reference to a child elementbase_iterator& operator++()
- incrementbool operator==(const base_iterator& a_it) const
- comparisonbool operator!=(const base_iterator& a_it) const
- comparison
The class object contains a value that has a type - one of the enum fcf::UnionType. The class object provides the functionality of bidirectional type conversion and the ability to JSON serialize.
- --- Constructors ---
Union()
- Initializes tofcf::undefined
Union(UnionType a_type)
- Initializes a new object with the given type.template <typename Ty> Union(const Ty& a_value)
- Initializes a new object with the given value- --- Base methods ---
template <typename Ty> bool is() const
- Returnstrue
ifTy
type is equal to the type of the stored object valuebool is(fcf::UnionType a_type) const
- Returnstrue
if type indexa_type
is equal to the type of the stored object valuetemplate <typename Ty> bool isCompatible(bool a_stringifyMode = false) const
- Returnstrue
if the stored value can be represented as typeTy
. If thea_stringifyMode
argument istrue
, the possibility of converting from string type to typeTy
is also checked.bool isCompatible(fcf::UnionType a_type, bool a_stringifyMode = false) const
- Returns true if the stored value can be represented as typea_type
. If thea_stringifyMode
argument istrue
, the possibility of converting from string type to typea_type
is also checked.template <typename Ty> explicit operator Ty() const
- Returns the stored value in the Ty type representation. If the stored value cannot be converted, anfcf::UnionException
exception is thrown.template <typename Ty> Ty get() const
- Returns the stored value in the Ty type representation. If the stored value cannot be converted, anfcf::UnionException
exception is thrown.template <typename Ty> fcf::Details::NUnion::TypeHelper<Ty>::far_type& ref()
- Returns a reference to the stored value. If the stored value differs from the requested type, the stored data type is converted to the closest available type and a reference to the stored value is returned. If the conversion process fails, the object is initialized to an empty value.template <typename Ty> void set(const Ty& a_value)
- Sets a new value.void set(const fcf::Union& a_value)
- Sets a new value.template <typename Ty> void set()
- Sets a new empty value with the given typevoid set(fcf::UnionType a_type)
- Sets a new empty value with the given typetemplate <typename Ty> fcf::Union& operator=(const Ty& a_value)
- Sets a new value.fcf::Union& operator=(const fcf::Union& a_union)
- Sets a new value.template <typename Ty> bool equal(const Ty& a_value, bool a_strict, bool a_deep) const
- Returnstrue
if the stored value is equal toa_value
. Ifa_strict
istrue
, then a strict comparison is performed (types must match). If thea_deep
parameter istrue
, then an element-wise comparison is performed forfcf::UnionVector
andfcf::UnionMap
.template <typename Ty> bool operator==(const Ty& a_value) const
- Performs a non-strict and non-deep equality comparison. Returnstrue
if the stored value is equal toa_value
.template <typename Ty> bool operator!=(const Ty& a_value) const
- Performs a non-strict and non-deep non-equality comparison. Returnstrue
if the stored value is not equal toa_value
.- --- Serialization methods ---
void stringify(std::string& a_dest, const fcf::UnionStringifyOptions& a_options = fcf::UnionStringifyOptions{}) const
- Saves the stored data to the variablea_dest
in JSON formatvoid stringify(std::basic_ostream<char>& a_dest, const UnionStringifyOptions& a_options = UnionStringifyOptions{}) const
- Saves the stored data to thea_dest
stream in JSON formatvoid parse(const std::string& a_source)
- Parses a JSON string. The original format may have deviations from JSON (like JS): may contain comments; may contain a comma after the last element; object keys do not have to be enclosed in quotes.void parse(std::basic_istream<char>& a_source)
- Parses a JSON stream. The original format may have deviations from JSON (like JS): may contain comments; may contain a comma after the last element; object keys do not have to be enclosed in quotes.- --- Accessing child elements ---
size_t size() const
- Returns the number of child elementsfcf::Union::iterator find(fcf::Union a_key)
- Searches for a child element by key. Returns an iterator to the found element. If the element is not found, returns an iterator to the end (Union::end()
)fcf::Union& at(fcf::Union a_key)
- Returns a reference to a child element by key. If the child element is not found, then forfcf::UnionVector
andfcf::UnionMap
an element is created, and for other types anfcf::UnionException
is thrown.const fcf::Union& cat(fcf::Union a_key) const
- Returns a const reference to a child element by key. If the child element is not found, anfcf::UnionException
is thrown.fcf::Union& operator[](fcf::Union a_key)
- Returns a reference to a child element by key. If the child element is not found, then forfcf::UnionVector
andfcf::UnionMap
an element is created, and for other types anfcf::UnionException
is thrown.fcf::Union::iterator insert(fcf::Union a_value)
- Inserts a new child element into the object and returns a iterator to it. The key of the new element will be equal to its ordinal in the object - thesize()
value before incrementing. If the object is not a container (fcf::UT_VECTOR
|fcf::UT_MAP
), thenfcf::UnionException
is thrown.fcf::Union::iterator insert(fcf::Union a_key, fcf::Union a_value)
- Inserts a new child element into the object and returns a iterator to it. If the object is not a container (fcf::UT_VECTOR
|fcf::UT_MAP
), thenfcf::UnionException
is thrown.fcf::Union::iterator erase(const fcf::Union& a_key)
- Removes an element by key. Returns an iterator to the next element. If the element is not found, the function returnsend()
fcf::Union::iterator erase(const fcf::Union::iterator& a_iterator)
- Removes an element. Returns an iterator to the next element. If the element is not found, the function returnsend()
.- --- Iterators ---
fcf::Union::iterator begin()
- Returns an iterator to the first child elementfcf::Union::iterator end()
- Returns an iterator to endfcf::Union::const_iterator cbegin() const
- Returns an const iterator to the first child elementfcf::Union::const_iterator cend() const
- Returns an const iterator to endfcf::Union::iterator obegin()
- Returns an iterator to the first child element, preserving sequence. If thefcf::Union
object is anfcf::UnionMap
, then the elements are iterated in the order they were added. For other types the method is similar tobegin()
.fcf::Union::iterator oend()
- Returns an iterator to endfcf::Union::const_iterator cobegin() const
- Returns an const iterator to the first child element, preserving sequence. If thefcf::Union
object is anfcf::UnionMap
, then the elements are iterated in the order they were added. For other types the method is similar tocbegin()
.fcf::Union::const_iterator coend() const
- Returns an const iterator to end