Skip to content
Snippets Groups Projects
Commit c0d70466 authored by hcasse's avatar hcasse
Browse files

Added io::StructuredOutput interface.

Added type testing test-types.
README.DEV converted to MD.
json::Saver changed to support StructuredOutput interface.
parent 64bdced6
No related branches found
No related tags found
No related merge requests found
====== Elm Developper Information ======
# Elm Developper Information
===== Organization =====
## Organization
Directories:
* include/ ELM headers.
......@@ -9,23 +9,17 @@ Directories:
* perf/ Performances test programs and data.
* tools/ Tool to work with ELM.
===== Working with sources =====
## Working with sources
Bootstrap:
<code sh>
cmake .
</code>
Under Windows (MINGW required):
<code sh>
cmake . -G "MSYS Makefiles"
</code>
Auto-documentation:
<code>
doxygen
xdg-open autodoc/index.html
</code>
Activating the test compilation:
cmake . -DWITH_TEST=yes
......@@ -39,16 +33,16 @@ Under Windows:
move src/libelm.dll to test/
===== Documentation =====
## Documentation
All classes, function, macros, variable or type provided
to uses must be documented using the [[http://www.stack.nl/~dimitri/doxygen/|Doxygen]]
to uses must be documented using the [Doxygen](http://www.stack.nl/~dimitri/doxygen/|Doxygen)
tool. Doxygen automatic documentation is very close to JavaDoc but provides
more flexibility and support for C++. The syntax detail can be found
[[http://www.stack.nl/~dimitri/doxygen/manual/commands.html|here]].
[here](http://www.stack.nl/~dimitri/doxygen/manual/commands.html).
Additionally, Doxygen supports Markdown wiki syntax that may be found
[[http://daringfireball.net/projects/markdown/syntax|here]]. Below is a non-exhaustive
[here](http://daringfireball.net/projects/markdown/syntax). Below is a non-exhaustive
list of markdown syntax:
* \n to create a new paragraph,
* title \n ==== or # title # to create a section
......@@ -70,33 +64,49 @@ list of markdown syntax:
An important rule must be applied: no documentation must be put in the header
file. Classes has to be described in the source file. For a class, a special comment
like below must be set:
<code c++>
/**
* @class MY_CLASS
* documentation
*/
</code>
For an inlined function, the documentation must be put in the source file as:
<code c++>
/**
* @fn RETURN_TYPE MY_CLASS::FUNCTION_NAME(PARAMETERS);
* documentation
*/
</code>
All resources provided by ELM must be located in a module using the Doxygen
directive @ingroup (at the end of the description):
<code c++>
/**
* documentation
* @ingroup MODULE
*/
</code>
The list of available modules may be obtained from the automatic documentation.
===== Development Directives =====
## Covering Types
In order, to get functions or template specializations supporting all types,
the following overload must be performed.
For base types:
* void
* bool
* char (special case for character support)
* signed/unsigned char/short/int/long/long long
* float, double, long double
For string types:
* const char *
* cstring
* const string&
Other type support encompasses:
* T * - pointer type
* const T& - other kind of object
## Development Directives
/*
* StructuredOutput class interface
*
* This file is part of OTAWA
* Copyright (c) 2021, IRIT UPS.
*
* OTAWA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OTAWA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OTAWA; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ELM_IO_STRUCTURED_OUTPUT_H
#define ELM_IO_STRUCTURED_OUTPUT_H
#include <elm/types.h>
namespace elm { namespace io {
class StructuredOutput {
public:
virtual ~StructuredOutput();
virtual void write(bool x) = 0;
virtual void write(char c) = 0;
virtual void write(signed char) = 0;
virtual void write(unsigned char) = 0;
virtual void write(short x) = 0;
virtual void write(unsigned short x) = 0;
virtual void write(int x) = 0;
virtual void write(unsigned int x) = 0;
virtual void write(long x) = 0;
virtual void write(unsigned long x) = 0;
virtual void write(long long int x) = 0;
virtual void write(long long unsigned int x) = 0;
virtual void write(float x) = 0;
virtual void write(double x) = 0;
virtual void write(long double x) = 0;
virtual void write(const char *s) = 0;
virtual void write(cstring x) = 0;
virtual void write(const string& x) = 0;
virtual void key(cstring x) = 0;
virtual void key(const string& x) = 0;
virtual void beginMap() = 0;
virtual void endMap() = 0;
virtual void beginList() = 0;
virtual void endList() = 0;
};
}} // otawa::io
#endif // ELM_IO_STRUCTURED_OUTPUT_H
......@@ -24,13 +24,14 @@
#include <elm/data/Vector.h>
#include <elm/io.h>
#include <elm/io/BufferedOutStream.h>
#include <elm/io/StructuredOutput.h>
#include <elm/string/utf8.h>
#include <elm/sys/Path.h>
#include "common.h"
namespace elm { namespace json {
class Saver {
class Saver: public io::StructuredOutput {
public:
Saver(io::OutStream& out = io::out);
Saver(StringBuffer& buf);
......@@ -43,21 +44,49 @@ public:
inline string getIndent(void) const { return indent; }
inline void setIndent(string i) { indent = i; }
void beginObject(void);
void endObject(void);
void beginArray(void);
void endArray(void);
void addField(string id);
// deprecated
inline void beginObject(void) { beginMap(); }
inline void endObject(void) { endMap(); }
inline void beginArray(void) { beginList(); }
inline void endArray(void) { endList(); }
inline void addField(string id) { key(id); }
// deprecated
void put(void);
inline void put(const char *val) { put(cstring(val)); }
void put(cstring val);
void put(string val);
void put(t::uint64 val);
void put(t::int64 val);
inline void put(cstring val) { write(val); }
inline void put(string val) { write(val); }
inline void put(t::uint64 val) { write(val); }
inline void put(t::int64 val) { write(val); }
inline void put(int val) { put(t::int64(val)); }
void put(double val);
void put(bool val);
inline void put(double val) { write(val); }
inline void put(bool val) { write(val); }
// StructuredOutput interface
virtual void write(bool x) override;
virtual void write(char c) override;
virtual void write(signed char x) override;
virtual void write(unsigned char x) override;
virtual void write(short x) override;
virtual void write(unsigned short x) override;
virtual void write(int x) override;
virtual void write(unsigned int x) override;
virtual void write(long x) override;
virtual void write(unsigned long x) override;
virtual void write(long long int x) override;
virtual void write(long long unsigned int x) override;
virtual void write(float x) override;
virtual void write(double x) override;
virtual void write(long double x) override;
virtual void write(const char *s) override;
virtual void write(cstring x) override;
virtual void write(const string& x) override;
virtual void key(cstring x) override;
virtual void key(const string& x) override;
virtual void beginMap() override;
virtual void endMap() override;
virtual void beginList() override;
virtual void endList() override;
private:
typedef enum {
......@@ -75,6 +104,7 @@ private:
static bool isObject(state_t s);
static bool isArray(state_t s);
void escape(utf8::char_t c);
inline void nextByValue(void);
state_t state;
Vector<state_t> stack;
......
......@@ -67,6 +67,7 @@ set(LIBELM_LA_SOURCES
"io_OutStream.cpp"
"io_RandomAccessStream.cpp"
"io_StreamPipe.cpp"
"io_StructuredOutput.cpp"
"io_TeeOutStream.cpp"
"io_UnixInStream.cpp"
"io_UnixOutStream.cpp"
......
/*
* StructuredOutput class implementation
*
* This file is part of OTAWA
* Copyright (c) 2021, IRIT UPS.
*
* OTAWA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OTAWA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OTAWA; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <elm/io/StructuredOutput.h>
namespace elm { namespace io {
/**
* @class StructuredOutput
*
* This interface is implemented to be performed structure output, that is the
* output of values orgznized as:
* * base types (integer, float, boolean, string)
* * list of values
* * map of values with string keys.
*
* Classical structured outputs encompasses [JSON](https://en.wikipedia.org/wiki/JSON),
* [XML](https://en.wikipedia.org/wiki/XML) or
* (INI)[https://en.wikipedia.org/wiki/INI_file].
*
* Base types are simply written by a call to a write() function.
*
* To write an list, perform a call to beginList(), as many call to write the
* items composing the list and closing is performed by calling endList().
*
* To write a map, perform a call to beginMap() and the, for each map value,
* * perform a call to key() with key name
* * and a call to a write function with the value.
* The map is completed by a call to endMap().
*
* This interface is currently implemented by:
* * elm::json::Saver
*
* @ingroup io
*/
///
StructuredOutput::~StructuredOutput() {
}
}}
......@@ -76,6 +76,32 @@ Saver::~Saver(void) {
delete str;
}
///
void Saver::nextByValue() {
switch(state) {
case BEGIN:
state = END;
break;
case OBJECT:
case IN_OBJECT:
ASSERTP(false, "json: value cannot be put in map without key");
break;
case FIELD:
stack.pop();
state = IN_OBJECT;
break;
case ARRAY:
state = IN_ARRAY;
break;
case IN_ARRAY:
break;
case END:
ASSERTP(false, "json: ended output!");
break;
}
}
/**
* Close the JSON output.
*/
......@@ -159,7 +185,7 @@ bool Saver::isArray(state_t s) {
* Begin an object. Only allowed at the beginning of the output,
* after adding an object or inside an array.
*/
void Saver::beginObject(void) {
void Saver::beginMap(void) {
ASSERTP(state != END, "json: ended output!");
ASSERTP(!isObject(state), "json: object creation only allowed in a field or an array");
doIndent();
......@@ -172,7 +198,7 @@ void Saver::beginObject(void) {
/**
* End an object. Only allowed inside an object.
*/
void Saver::endObject(void) {
void Saver::endMap(void) {
ASSERTP(isObject(state), "json: not inside an object!");
if(!stack)
state = END;
......@@ -185,7 +211,7 @@ void Saver::endObject(void) {
/**
* Begin an array. Only allowed inside an array or in a field.
*/
void Saver::beginArray(void) {
void Saver::beginList(void) {
ASSERTP(state != END, "json: ended output!");
ASSERTP(state == FIELD || isArray(state), "json: array only allowed in a field or in an array");
doIndent();
......@@ -198,7 +224,7 @@ void Saver::beginArray(void) {
/**
* End an array. Only allowed inside an array.
*/
void Saver::endArray(void) {
void Saver::endList(void) {
ASSERTP(isArray(state), "json: not inside an array!");
state_t new_state = next(stack.pop());
state = ARRAY;
......@@ -210,7 +236,30 @@ void Saver::endArray(void) {
/**
* Add a field. Only allowed inside an object.
*/
void Saver::addField(string id) {
void Saver::key(const string& id) {
ASSERTP(isObject(state), "json: field only allowed inside an object!");
doIndent();
_out << '"';
try {
for(utf8::Iter i(id); i(); i++)
escape(*i);
}
catch(utf8::Exception& e) {
ASSERTP(false, _ << "json: bad utf8 string: \"" << id << "\"");
}
_out << '"';
if(isReadable())
_out << ": ";
else
_out << ":";
stack.push(state);
state = FIELD;
}
/**
* Add a field. Only allowed inside an object.
*/
void Saver::key(cstring id) {
ASSERTP(isObject(state), "json: field only allowed inside an object!");
doIndent();
_out << '"';
......@@ -266,31 +315,31 @@ void Saver::put(void) {
}
/**
* Put a string value.
* @param str String to put.
* Put a boolean value.
* @param val Value to put.
*/
void Saver::put(cstring str) {
void Saver::write(bool val) {
ASSERTP(state == FIELD || isArray(state), "json: cannot put a value out of a field or an array!");
doIndent();
_out << '"';
for(utf8::Iter i(str); i(); i++)
escape(*i);
_out << '"';
if(val)
_out << "true";
else
_out << "false";
if(state == FIELD)
state = stack.pop();
state = next(state);
}
/**
* Put a string value.
* @param val String to put.
* Put a character value.
* @param chr Character to put.
*/
void Saver::put(string val) {
void Saver::write(char c) {
ASSERTP(state == FIELD || isArray(state), "json: cannot put a value out of a field or an array!");
doIndent();
_out << '"';
for(utf8::Iter i(val); i(); i++)
escape(*i);
escape(c);
_out << '"';
if(state == FIELD)
state = stack.pop();
......@@ -298,58 +347,82 @@ void Saver::put(string val) {
}
/**
* Put an integer value.
* @param val Value to put.
* Put a string value.
* @param str String to put.
*/
void Saver::put(t::uint64 val) {
ASSERTP(state == FIELD || isArray(state), "json: cannot put a value out of a field or an array!");
doIndent();
_out << val;
if(state == FIELD)
state = stack.pop();
state = next(state);
void Saver::write(const char *str) {
write(cstring(str));
}
/**
* Put an integer value.
* @param val Value to put.
* Put a string value.
* @param str String to put.
*/
void Saver::put(t::int64 val) {
void Saver::write(cstring str) {
ASSERTP(state == FIELD || isArray(state), "json: cannot put a value out of a field or an array!");
doIndent();
_out << val;
_out << '"';
for(utf8::Iter i(str); i(); i++)
escape(*i);
_out << '"';
if(state == FIELD)
state = stack.pop();
state = next(state);
}
/**
* Put a double value.
* @param val Value to put.
* Put a string value.
* @param val String to put.
*/
void Saver::put(double val) {
void Saver::write(const string& val) {
ASSERTP(state == FIELD || isArray(state), "json: cannot put a value out of a field or an array!");
doIndent();
_out << val;
_out << '"';
for(utf8::Iter i(val); i(); i++)
escape(*i);
_out << '"';
if(state == FIELD)
state = stack.pop();
state = next(state);
}
/**
* Put a boolean value.
* @param val Value to put.
*/
void Saver::put(bool val) {
ASSERTP(state == FIELD || isArray(state), "json: cannot put a value out of a field or an array!");
doIndent();
if(val)
_out << "true";
else
_out << "false";
if(state == FIELD)
state = stack.pop();
state = next(state);
}
///
void Saver::write(signed char x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(unsigned char x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(signed short x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(unsigned short x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(signed int x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(unsigned int x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(signed long x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(unsigned long x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(signed long long x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(unsigned long long x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(float x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(double x) { doIndent(); nextByValue(); _out << x; }
///
void Saver::write(long double x) { doIndent(); nextByValue(); _out << x; }
} } // json
......@@ -121,3 +121,6 @@ target_link_libraries(test_bgc elm)
add_executable(test_thread "thread.cpp")
target_link_libraries(test_thread elm)
add_executable(test-types "test-types.cpp")
target_link_libraries(test-types elm)
/*
* Test types for overloading.
*
* This file is part of OTAWA
* Copyright (c) 2021, IRIT UPS.
*
* OTAWA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* OTAWA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OTAWA; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <elm/types.h>
#include <elm/io.h>
using namespace elm;
#define F(t) void f(t i) { cout << #t << io::endl; }
F(bool)
F(char)
F(unsigned char)
F(signed char)
F(int)
F(unsigned int)
F(short)
F(unsigned short)
F(long)
F(unsigned long)
F(long long)
F(unsigned long long)
F(float);
F(double);
F(long double);
int main() {
cout << "ELM types" << io::endl;
cout << "sizeof(t::int8) = " << sizeof(t::int8) << io::endl;
cout << "sizeof(t::uint8) = " << sizeof(t::uint8) << io::endl;
cout << "sizeof(t::int16) = " << sizeof(t::int16) << io::endl;
cout << "sizeof(t::uint16) = " << sizeof(t::uint16) << io::endl;
cout << "sizeof(t::int32) = " << sizeof(t::int32) << io::endl;
cout << "sizeof(t::uint32) = " << sizeof(t::uint32) << io::endl;
cout << "sizeof(t::int64) = " << sizeof(t::int64) << io::endl;
cout << "sizeof(t::uint64) = " << sizeof(t::uint64) << io::endl;
cout << io::endl << "immediate types" << io::endl;
cout << "sizeof(111) = " << sizeof(111) << io::endl;
cout << "sizeof(111U) = " << sizeof(111U) << io::endl;
cout << "sizeof(111L) = " << sizeof(111L) << io::endl;
cout << "sizeof(111UL) = " << sizeof(111UL) << io::endl;
cout << "sizeof(111LL) = " << sizeof(111LL) << io::endl;
cout << "sizeof(111ULL) = " << sizeof(111ULL) << io::endl;
cout << io::endl << "basic types" << io::endl;
cout << "sizeof(char) = " << sizeof(char) << io::endl;
cout << "sizeof(signed char) = " << sizeof(signed char) << io::endl;
cout << "sizeof(unsigned char) = " << sizeof(unsigned char) << io::endl;
cout << "sizeof(int) = " << sizeof(int) << io::endl;
cout << "sizeof(signed int) = " << sizeof(signed int) << io::endl;
cout << "sizeof(unsigned int) = " << sizeof(unsigned int) << io::endl;
cout << "sizeof(signed) = " << sizeof(signed) << io::endl;
cout << "sizeof(unsigned) = " << sizeof(unsigned) << io::endl;
cout << "sizeof(short) = " << sizeof(short) << io::endl;
cout << "sizeof(signed short) = " << sizeof(signed short) << io::endl;
cout << "sizeof(unsigned short) = " << sizeof(unsigned short) << io::endl;
cout << "sizeof(long) = " << sizeof(long) << io::endl;
cout << "sizeof(signed long) = " << sizeof(signed long) << io::endl;
cout << "sizeof(unsigned long) = " << sizeof(unsigned long) << io::endl;
cout << "sizeof(long long) = " << sizeof(long long) << io::endl;
cout << "sizeof(signed long long) = " << sizeof(signed long long) << io::endl;
cout << "sizeof(unsigned long long) = " << sizeof(unsigned long long) << io::endl;
cout << io::endl << "constant overloading" << io::endl;
cout << "'a' "; f('a');
cout << "true "; f(true);
cout << "111 "; f(111);
cout << "111U "; f(111U);
cout << "111L "; f(111L);
cout << "111UL "; f(111UL);
cout << "111LL "; f(111LL);
cout << "111ULL "; f(111ULL);
cout << "0. "; f(0.);
cout << "0.F "; f(0.F);
cout << "0.L "; f(0.L);
cout << io::endl << "t:: overloading" << io::endl;
{ bool x = false; f(x); }
{ char x = 0; f(x); }
{ t::int8 x = 0; f(x); }
{ t::uint8 x = 0; f(x); }
{ t::int16 x = 0; f(x); }
{ t::uint16 x = 0; f(x); }
{ t::int32 x = 0; f(x); }
{ t::uint32 x = 0; f(x); }
{ t::int64 x = 0; f(x); }
{ t::uint64 x = 0; f(x); }
{ signed x = 0; f(x); }
{ unsigned x = 0; f(x); }
{ float x = 0; f(x); }
{ double x = 0; f(x); }
{ long double x = 0; f(x); }
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment