summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt12
-rwxr-xr-xlib/download_dependencies.sh10
-rw-r--r--lib/utf8cpp/utf8.h34
-rw-r--r--lib/utf8cpp/utf8/checked.h327
-rw-r--r--lib/utf8cpp/utf8/core.h329
-rw-r--r--lib/utf8cpp/utf8/unchecked.h228
-rw-r--r--src/core/common/Variant.cpp14
-rw-r--r--src/core/common/VariantReader.cpp157
-rw-r--r--src/core/managed/Managed.hpp25
-rw-r--r--src/core/managed/ManagedType.hpp119
-rw-r--r--src/core/managed/Rtti.cpp (renamed from src/core/managed/ManagedType.cpp)32
-rw-r--r--src/core/managed/Rtti.hpp183
-rw-r--r--src/core/model/Typesystem.cpp51
-rw-r--r--src/core/model/Typesystem.hpp171
-rw-r--r--test/core/common/VariantReaderTest.cpp65
-rw-r--r--test/core/managed/ManagedTest.cpp36
-rw-r--r--test/core/managed/RttiTest.cpp63
-rw-r--r--test/core/model/TypesystemTest.cpp104
18 files changed, 1661 insertions, 299 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 077ac47..371ffca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,12 +32,17 @@ OPTION(BUILD_DOCUMENTATION "Create and install the HTML based API documentation
# Enable C++11 and all warnings
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic-errors -std=c++11")
-# Include boost (filesystem) expat and mozjs-24 via PkgConfig
+# Include expat and mozjs-24 via PkgConfig
FIND_PACKAGE(PkgConfig REQUIRED)
PKG_CHECK_MODULES(MOZJS REQUIRED mozjs-24)
PKG_CHECK_MODULES(EXPAT REQUIRED expat)
+
+# Include required Boost components using the Boost cmake package
FIND_PACKAGE(Boost COMPONENTS system filesystem REQUIRED)
+# Set utf8cpp include path
+SET(UTF8CPP_INCLUDE_DIR "lib/utf8")
+
################################################################################
# Inclusion of doxygen #
################################################################################
@@ -87,6 +92,7 @@ INCLUDE_DIRECTORIES(
${MOZJS_INCLUDE_DIRS}
${EXPAT_INCLUDE_DIRS}
${Boost_INCLUDE_DIR}
+ ${UTF8CPP_INCLUDE_DIR}
)
# Link directories
@@ -112,8 +118,8 @@ ADD_LIBRARY(ousia_core
src/core/common/Variant
src/core/common/VariantReader
src/core/managed/Managed
- src/core/managed/ManagedType
src/core/managed/Manager
+ src/core/managed/Rtti
src/core/model/Document
src/core/model/Domain
src/core/model/Typesystem
@@ -184,8 +190,10 @@ IF(TEST)
test/core/managed/ManagedContainerTest
test/core/managed/ManagedTest
test/core/managed/ManagerTest
+ test/core/managed/RttiTest
test/core/model/DomainTest
test/core/model/DocumentTest
+ test/core/model/TypesystemTest
test/core/parser/ParserStackTest
# test/core/script/FunctionTest
# test/core/script/ObjectTest
diff --git a/lib/download_dependencies.sh b/lib/download_dependencies.sh
index 369c514..8217dd7 100755
--- a/lib/download_dependencies.sh
+++ b/lib/download_dependencies.sh
@@ -1,6 +1,12 @@
#!/bin/sh
# Download and unzip googletest
-wget https://googletest.googlecode.com/files/gtest-1.7.0.zip
-unzip gtest-1.7.0.zip
+if [ ! -e gtest-1.7.0.zip ]; then
+ wget https://googletest.googlecode.com/files/gtest-1.7.0.zip
+ unzip gtest-1.7.0.zip
+fi
+# Download utf8-cpp (header only library)
+if [ ! -e utf8cpp ]; then
+ svn checkout svn://svn.code.sf.net/p/utfcpp/code/v2_0/source utf8cpp
+fi
diff --git a/lib/utf8cpp/utf8.h b/lib/utf8cpp/utf8.h
new file mode 100644
index 0000000..4e44514
--- /dev/null
+++ b/lib/utf8cpp/utf8.h
@@ -0,0 +1,34 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "utf8/checked.h"
+#include "utf8/unchecked.h"
+
+#endif // header guard
diff --git a/lib/utf8cpp/utf8/checked.h b/lib/utf8cpp/utf8/checked.h
new file mode 100644
index 0000000..1331155
--- /dev/null
+++ b/lib/utf8cpp/utf8/checked.h
@@ -0,0 +1,327 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+#include <stdexcept>
+
+namespace utf8
+{
+ // Base for the exceptions that may be thrown from the library
+ class exception : public ::std::exception {
+ };
+
+ // Exceptions that may be thrown from the library functions.
+ class invalid_code_point : public exception {
+ uint32_t cp;
+ public:
+ invalid_code_point(uint32_t cp) : cp(cp) {}
+ virtual const char* what() const throw() { return "Invalid code point"; }
+ uint32_t code_point() const {return cp;}
+ };
+
+ class invalid_utf8 : public exception {
+ uint8_t u8;
+ public:
+ invalid_utf8 (uint8_t u) : u8(u) {}
+ virtual const char* what() const throw() { return "Invalid UTF-8"; }
+ uint8_t utf8_octet() const {return u8;}
+ };
+
+ class invalid_utf16 : public exception {
+ uint16_t u16;
+ public:
+ invalid_utf16 (uint16_t u) : u16(u) {}
+ virtual const char* what() const throw() { return "Invalid UTF-16"; }
+ uint16_t utf16_word() const {return u16;}
+ };
+
+ class not_enough_room : public exception {
+ public:
+ virtual const char* what() const throw() { return "Not enough space"; }
+ };
+
+ /// The library API - functions intended to be called by the users
+
+ template <typename octet_iterator>
+ octet_iterator append(uint32_t cp, octet_iterator result)
+ {
+ if (!utf8::internal::is_code_point_valid(cp))
+ throw invalid_code_point(cp);
+
+ if (cp < 0x80) // one octet
+ *(result++) = static_cast<uint8_t>(cp);
+ else if (cp < 0x800) { // two octets
+ *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else if (cp < 0x10000) { // three octets
+ *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else { // four octets
+ *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
+ *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename output_iterator>
+ output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
+ {
+ while (start != end) {
+ octet_iterator sequence_start = start;
+ internal::utf_error err_code = utf8::internal::validate_next(start, end);
+ switch (err_code) {
+ case internal::UTF8_OK :
+ for (octet_iterator it = sequence_start; it != start; ++it)
+ *out++ = *it;
+ break;
+ case internal::NOT_ENOUGH_ROOM:
+ throw not_enough_room();
+ case internal::INVALID_LEAD:
+ out = utf8::append (replacement, out);
+ ++start;
+ break;
+ case internal::INCOMPLETE_SEQUENCE:
+ case internal::OVERLONG_SEQUENCE:
+ case internal::INVALID_CODE_POINT:
+ out = utf8::append (replacement, out);
+ ++start;
+ // just one replacement mark for the sequence
+ while (start != end && utf8::internal::is_trail(*start))
+ ++start;
+ break;
+ }
+ }
+ return out;
+ }
+
+ template <typename octet_iterator, typename output_iterator>
+ inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
+ {
+ static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
+ return utf8::replace_invalid(start, end, out, replacement_marker);
+ }
+
+ template <typename octet_iterator>
+ uint32_t next(octet_iterator& it, octet_iterator end)
+ {
+ uint32_t cp = 0;
+ internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
+ switch (err_code) {
+ case internal::UTF8_OK :
+ break;
+ case internal::NOT_ENOUGH_ROOM :
+ throw not_enough_room();
+ case internal::INVALID_LEAD :
+ case internal::INCOMPLETE_SEQUENCE :
+ case internal::OVERLONG_SEQUENCE :
+ throw invalid_utf8(*it);
+ case internal::INVALID_CODE_POINT :
+ throw invalid_code_point(cp);
+ }
+ return cp;
+ }
+
+ template <typename octet_iterator>
+ uint32_t peek_next(octet_iterator it, octet_iterator end)
+ {
+ return utf8::next(it, end);
+ }
+
+ template <typename octet_iterator>
+ uint32_t prior(octet_iterator& it, octet_iterator start)
+ {
+ // can't do much if it == start
+ if (it == start)
+ throw not_enough_room();
+
+ octet_iterator end = it;
+ // Go back until we hit either a lead octet or start
+ while (utf8::internal::is_trail(*(--it)))
+ if (it == start)
+ throw invalid_utf8(*it); // error - no lead byte in the sequence
+ return utf8::peek_next(it, end);
+ }
+
+ /// Deprecated in versions that include "prior"
+ template <typename octet_iterator>
+ uint32_t previous(octet_iterator& it, octet_iterator pass_start)
+ {
+ octet_iterator end = it;
+ while (utf8::internal::is_trail(*(--it)))
+ if (it == pass_start)
+ throw invalid_utf8(*it); // error - no lead byte in the sequence
+ octet_iterator temp = it;
+ return utf8::next(temp, end);
+ }
+
+ template <typename octet_iterator, typename distance_type>
+ void advance (octet_iterator& it, distance_type n, octet_iterator end)
+ {
+ for (distance_type i = 0; i < n; ++i)
+ utf8::next(it, end);
+ }
+
+ template <typename octet_iterator>
+ typename std::iterator_traits<octet_iterator>::difference_type
+ distance (octet_iterator first, octet_iterator last)
+ {
+ typename std::iterator_traits<octet_iterator>::difference_type dist;
+ for (dist = 0; first < last; ++dist)
+ utf8::next(first, last);
+ return dist;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::internal::mask16(*start++);
+ // Take care of surrogate pairs first
+ if (utf8::internal::is_lead_surrogate(cp)) {
+ if (start != end) {
+ uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+ if (utf8::internal::is_trail_surrogate(trail_surrogate))
+ cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+ else
+ throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
+ }
+ else
+ throw invalid_utf16(static_cast<uint16_t>(cp));
+
+ }
+ // Lone trail surrogate
+ else if (utf8::internal::is_trail_surrogate(cp))
+ throw invalid_utf16(static_cast<uint16_t>(cp));
+
+ result = utf8::append(cp, result);
+ }
+ return result;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::next(start, end);
+ if (cp > 0xffff) { //make a surrogate pair
+ *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
+ *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+ }
+ else
+ *result++ = static_cast<uint16_t>(cp);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+ {
+ while (start != end)
+ result = utf8::append(*(start++), result);
+
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+ {
+ while (start != end)
+ (*result++) = utf8::next(start, end);
+
+ return result;
+ }
+
+ // The iterator class
+ template <typename octet_iterator>
+ class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+ octet_iterator it;
+ octet_iterator range_start;
+ octet_iterator range_end;
+ public:
+ iterator () {}
+ explicit iterator (const octet_iterator& octet_it,
+ const octet_iterator& range_start,
+ const octet_iterator& range_end) :
+ it(octet_it), range_start(range_start), range_end(range_end)
+ {
+ if (it < range_start || it > range_end)
+ throw std::out_of_range("Invalid utf-8 iterator position");
+ }
+ // the default "big three" are OK
+ octet_iterator base () const { return it; }
+ uint32_t operator * () const
+ {
+ octet_iterator temp = it;
+ return utf8::next(temp, range_end);
+ }
+ bool operator == (const iterator& rhs) const
+ {
+ if (range_start != rhs.range_start || range_end != rhs.range_end)
+ throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
+ return (it == rhs.it);
+ }
+ bool operator != (const iterator& rhs) const
+ {
+ return !(operator == (rhs));
+ }
+ iterator& operator ++ ()
+ {
+ utf8::next(it, range_end);
+ return *this;
+ }
+ iterator operator ++ (int)
+ {
+ iterator temp = *this;
+ utf8::next(it, range_end);
+ return temp;
+ }
+ iterator& operator -- ()
+ {
+ utf8::prior(it, range_start);
+ return *this;
+ }
+ iterator operator -- (int)
+ {
+ iterator temp = *this;
+ utf8::prior(it, range_start);
+ return temp;
+ }
+ }; // class iterator
+
+} // namespace utf8
+
+#endif //header guard
+
+
diff --git a/lib/utf8cpp/utf8/core.h b/lib/utf8cpp/utf8/core.h
new file mode 100644
index 0000000..693d388
--- /dev/null
+++ b/lib/utf8cpp/utf8/core.h
@@ -0,0 +1,329 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include <iterator>
+
+namespace utf8
+{
+ // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
+ // You may need to change them to match your system.
+ // These typedefs have the same names as ones from cstdint, or boost/cstdint
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+
+// Helper code - not intended to be directly called by the library users. May be changed at any time
+namespace internal
+{
+ // Unicode constants
+ // Leading (high) surrogates: 0xd800 - 0xdbff
+ // Trailing (low) surrogates: 0xdc00 - 0xdfff
+ const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
+ const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
+ const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
+ const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
+ const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
+ const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
+
+ // Maximum valid value for a Unicode code point
+ const uint32_t CODE_POINT_MAX = 0x0010ffffu;
+
+ template<typename octet_type>
+ inline uint8_t mask8(octet_type oc)
+ {
+ return static_cast<uint8_t>(0xff & oc);
+ }
+ template<typename u16_type>
+ inline uint16_t mask16(u16_type oc)
+ {
+ return static_cast<uint16_t>(0xffff & oc);
+ }
+ template<typename octet_type>
+ inline bool is_trail(octet_type oc)
+ {
+ return ((utf8::internal::mask8(oc) >> 6) == 0x2);
+ }
+
+ template <typename u16>
+ inline bool is_lead_surrogate(u16 cp)
+ {
+ return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
+ }
+
+ template <typename u16>
+ inline bool is_trail_surrogate(u16 cp)
+ {
+ return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+ }
+
+ template <typename u16>
+ inline bool is_surrogate(u16 cp)
+ {
+ return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+ }
+
+ template <typename u32>
+ inline bool is_code_point_valid(u32 cp)
+ {
+ return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
+ }
+
+ template <typename octet_iterator>
+ inline typename std::iterator_traits<octet_iterator>::difference_type
+ sequence_length(octet_iterator lead_it)
+ {
+ uint8_t lead = utf8::internal::mask8(*lead_it);
+ if (lead < 0x80)
+ return 1;
+ else if ((lead >> 5) == 0x6)
+ return 2;
+ else if ((lead >> 4) == 0xe)
+ return 3;
+ else if ((lead >> 3) == 0x1e)
+ return 4;
+ else
+ return 0;
+ }
+
+ template <typename octet_difference_type>
+ inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
+ {
+ if (cp < 0x80) {
+ if (length != 1)
+ return true;
+ }
+ else if (cp < 0x800) {
+ if (length != 2)
+ return true;
+ }
+ else if (cp < 0x10000) {
+ if (length != 3)
+ return true;
+ }
+
+ return false;
+ }
+
+ enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
+
+ /// Helper for get_sequence_x
+ template <typename octet_iterator>
+ utf_error increase_safely(octet_iterator& it, octet_iterator end)
+ {
+ if (++it == end)
+ return NOT_ENOUGH_ROOM;
+
+ if (!utf8::internal::is_trail(*it))
+ return INCOMPLETE_SEQUENCE;
+
+ return UTF8_OK;
+ }
+
+ #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
+
+ /// get_sequence_x functions decode utf-8 sequences of the length x
+ template <typename octet_iterator>
+ utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (*it) & 0x3f;
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (*it) & 0x3f;
+
+ return UTF8_OK;
+ }
+
+ #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
+
+ template <typename octet_iterator>
+ utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ // Save the original value of it so we can go back in case of failure
+ // Of course, it does not make much sense with i.e. stream iterators
+ octet_iterator original_it = it;
+
+ uint32_t cp = 0;
+ // Determine the sequence length based on the lead octet
+ typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
+ const octet_difference_type length = utf8::internal::sequence_length(it);
+
+ // Get trail octets and calculate the code point
+ utf_error err = UTF8_OK;
+ switch (length) {
+ case 0:
+ return INVALID_LEAD;
+ case 1:
+ err = utf8::internal::get_sequence_1(it, end, cp);
+ break;
+ case 2:
+ err = utf8::internal::get_sequence_2(it, end, cp);
+ break;
+ case 3:
+ err = utf8::internal::get_sequence_3(it, end, cp);
+ break;
+ case 4:
+ err = utf8::internal::get_sequence_4(it, end, cp);
+ break;
+ }
+
+ if (err == UTF8_OK) {
+ // Decoding succeeded. Now, security checks...
+ if (utf8::internal::is_code_point_valid(cp)) {
+ if (!utf8::internal::is_overlong_sequence(cp, length)){
+ // Passed! Return here.
+ code_point = cp;
+ ++it;
+ return UTF8_OK;
+ }
+ else
+ err = OVERLONG_SEQUENCE;
+ }
+ else
+ err = INVALID_CODE_POINT;
+ }
+
+ // Failure branch - restore the original value of the iterator
+ it = original_it;
+ return err;
+ }
+
+ template <typename octet_iterator>
+ inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
+ uint32_t ignored;
+ return utf8::internal::validate_next(it, end, ignored);
+ }
+
+} // namespace internal
+
+ /// The library API - functions intended to be called by the users
+
+ // Byte order mark
+ const uint8_t bom[] = {0xef, 0xbb, 0xbf};
+
+ template <typename octet_iterator>
+ octet_iterator find_invalid(octet_iterator start, octet_iterator end)
+ {
+ octet_iterator result = start;
+ while (result != end) {
+ utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
+ if (err_code != internal::UTF8_OK)
+ return result;
+ }
+ return result;
+ }
+
+ template <typename octet_iterator>
+ inline bool is_valid(octet_iterator start, octet_iterator end)
+ {
+ return (utf8::find_invalid(start, end) == end);
+ }
+
+ template <typename octet_iterator>
+ inline bool starts_with_bom (octet_iterator it, octet_iterator end)
+ {
+ return (
+ ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
+ ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
+ ((it != end) && (utf8::internal::mask8(*it)) == bom[2])
+ );
+ }
+
+ //Deprecated in release 2.3
+ template <typename octet_iterator>
+ inline bool is_bom (octet_iterator it)
+ {
+ return (
+ (utf8::internal::mask8(*it++)) == bom[0] &&
+ (utf8::internal::mask8(*it++)) == bom[1] &&
+ (utf8::internal::mask8(*it)) == bom[2]
+ );
+ }
+} // namespace utf8
+
+#endif // header guard
+
+
diff --git a/lib/utf8cpp/utf8/unchecked.h b/lib/utf8cpp/utf8/unchecked.h
new file mode 100644
index 0000000..cb24271
--- /dev/null
+++ b/lib/utf8cpp/utf8/unchecked.h
@@ -0,0 +1,228 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+
+namespace utf8
+{
+ namespace unchecked
+ {
+ template <typename octet_iterator>
+ octet_iterator append(uint32_t cp, octet_iterator result)
+ {
+ if (cp < 0x80) // one octet
+ *(result++) = static_cast<uint8_t>(cp);
+ else if (cp < 0x800) { // two octets
+ *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else if (cp < 0x10000) { // three octets
+ *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else { // four octets
+ *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
+ *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator>
+ uint32_t next(octet_iterator& it)
+ {
+ uint32_t cp = utf8::internal::mask8(*it);
+ typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
+ switch (length) {
+ case 1:
+ break;
+ case 2:
+ it++;
+ cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
+ break;
+ case 3:
+ ++it;
+ cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+ ++it;
+ cp += (*it) & 0x3f;
+ break;
+ case 4:
+ ++it;
+ cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+ ++it;
+ cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
+ ++it;
+ cp += (*it) & 0x3f;
+ break;
+ }
+ ++it;
+ return cp;
+ }
+
+ template <typename octet_iterator>
+ uint32_t peek_next(octet_iterator it)
+ {
+ return utf8::unchecked::next(it);
+ }
+
+ template <typename octet_iterator>
+ uint32_t prior(octet_iterator& it)
+ {
+ while (utf8::internal::is_trail(*(--it))) ;
+ octet_iterator temp = it;
+ return utf8::unchecked::next(temp);
+ }
+
+ // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
+ template <typename octet_iterator>
+ inline uint32_t previous(octet_iterator& it)
+ {
+ return utf8::unchecked::prior(it);
+ }
+
+ template <typename octet_iterator, typename distance_type>
+ void advance (octet_iterator& it, distance_type n)
+ {
+ for (distance_type i = 0; i < n; ++i)
+ utf8::unchecked::next(it);
+ }
+
+ template <typename octet_iterator>
+ typename std::iterator_traits<octet_iterator>::difference_type
+ distance (octet_iterator first, octet_iterator last)
+ {
+ typename std::iterator_traits<octet_iterator>::difference_type dist;
+ for (dist = 0; first < last; ++dist)
+ utf8::unchecked::next(first);
+ return dist;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::internal::mask16(*start++);
+ // Take care of surrogate pairs first
+ if (utf8::internal::is_lead_surrogate(cp)) {
+ uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+ cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+ }
+ result = utf8::unchecked::append(cp, result);
+ }
+ return result;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+ {
+ while (start < end) {
+ uint32_t cp = utf8::unchecked::next(start);
+ if (cp > 0xffff) { //make a surrogate pair
+ *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
+ *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+ }
+ else
+ *result++ = static_cast<uint16_t>(cp);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+ {
+ while (start != end)
+ result = utf8::unchecked::append(*(start++), result);
+
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+ {
+ while (start < end)
+ (*result++) = utf8::unchecked::next(start);
+
+ return result;
+ }
+
+ // The iterator class
+ template <typename octet_iterator>
+ class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+ octet_iterator it;
+ public:
+ iterator () {}
+ explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
+ // the default "big three" are OK
+ octet_iterator base () const { return it; }
+ uint32_t operator * () const
+ {
+ octet_iterator temp = it;
+ return utf8::unchecked::next(temp);
+ }
+ bool operator == (const iterator& rhs) const
+ {
+ return (it == rhs.it);
+ }
+ bool operator != (const iterator& rhs) const
+ {
+ return !(operator == (rhs));
+ }
+ iterator& operator ++ ()
+ {
+ ::std::advance(it, utf8::internal::sequence_length(it));
+ return *this;
+ }
+ iterator operator ++ (int)
+ {
+ iterator temp = *this;
+ ::std::advance(it, utf8::internal::sequence_length(it));
+ return temp;
+ }
+ iterator& operator -- ()
+ {
+ utf8::unchecked::prior(it);
+ return *this;
+ }
+ iterator operator -- (int)
+ {
+ iterator temp = *this;
+ utf8::unchecked::prior(it);
+ return temp;
+ }
+ }; // class iterator
+
+ } // namespace utf8::unchecked
+} // namespace utf8
+
+
+#endif // header guard
+
diff --git a/src/core/common/Variant.cpp b/src/core/common/Variant.cpp
index 6b99add..53286a2 100644
--- a/src/core/common/Variant.cpp
+++ b/src/core/common/Variant.cpp
@@ -132,10 +132,16 @@ Variant::stringType Variant::toString(bool escape) const
return "null";
case Type::BOOL:
return asBool() ? "true" : "false";
- case Type::INT:
- return std::to_string(asInt());
- case Type::DOUBLE:
- return std::to_string(asDouble());
+ case Type::INT: {
+ std::stringstream ss;
+ ss << asInt();
+ return ss.str();
+ }
+ case Type::DOUBLE: {
+ std::stringstream ss;
+ ss << asDouble();
+ return ss.str();
+ }
case Type::STRING: {
// TODO: Use proper serialization function
if (escape) {
diff --git a/src/core/common/VariantReader.cpp b/src/core/common/VariantReader.cpp
index cc25eac..ccc14f8 100644
--- a/src/core/common/VariantReader.cpp
+++ b/src/core/common/VariantReader.cpp
@@ -21,6 +21,8 @@
#include <cmath>
#include <sstream>
+#include <utf8.h>
+
#include "VariantReader.hpp"
#include "Utils.hpp"
@@ -79,11 +81,6 @@ static std::pair<bool, T> unexpected(CharReader &reader, Logger &logger,
class Number {
private:
/**
- * Reprsents the part of the number: Base value a, nominator n, exponent e.
- */
- enum class Part { A, N, E };
-
- /**
* State used in the parser state machine
*/
enum class State {
@@ -117,43 +114,12 @@ private:
return -1;
}
+public:
/**
- * Appends the value of the character c to the internal number
- * representation and reports any errors that might occur.
+ * Reprsents the part of the number: Base value a, nominator n, exponent e.
*/
- bool appendChar(char c, int base, Part p, CharReader &reader,
- Logger &logger)
- {
- // Check whether the given character is valid
- int v = charValue(c);
- if (v < 0 || v >= base) {
- logger.error(unexpectedMsg("digit", c), reader);
- return false;
- }
-
- // Append the number to the specified part
- switch (p) {
- case Part::A:
- a = a * base + v;
- break;
- case Part::N:
- n = n * base + v;
- d = d * base;
- break;
- case Part::E:
- e = e * base + v;
- break;
- }
-
- // Check for any overflows
- if (a < 0 || n < 0 || d < 0 || e < 0) {
- logger.error(ERR_TOO_LARGE, reader);
- return false;
- }
- return true;
- }
+ enum class Part { A, N, E };
-public:
/**
* Sign and exponent sign.
*/
@@ -196,12 +162,51 @@ public:
bool isInt() { return (n == 0) && (d == 1) && (e == 0); }
/**
+ * Appends the value of the character c to the internal number
+ * representation and reports any errors that might occur.
+ */
+ bool appendChar(char c, int base, Part p, CharReader &reader,
+ Logger &logger)
+ {
+ // Check whether the given character is valid
+ int v = charValue(c);
+ if (v < 0 || v >= base) {
+ logger.error(unexpectedMsg("digit", c), reader);
+ return false;
+ }
+
+ // Append the number to the specified part
+ switch (p) {
+ case Part::A:
+ a = a * base + v;
+ break;
+ case Part::N:
+ n = n * base + v;
+ d = d * base;
+ break;
+ case Part::E:
+ e = e * base + v;
+ break;
+ }
+
+ // Check for any overflows
+ if (a < 0 || n < 0 || d < 0 || e < 0) {
+ logger.error(ERR_TOO_LARGE, reader);
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Tries to parse the number from the given stream and loggs any errors to
* the given logger instance. Numbers are terminated by one of the given
* delimiters.
*/
bool parse(CharReader &reader, Logger &logger,
const std::unordered_set<char> &delims);
+
+ bool parseFixedLenInt(CharReader &reader, Logger &logger, int base,
+ int len);
};
bool Number::parse(CharReader &reader, Logger &logger,
@@ -332,6 +337,24 @@ bool Number::parse(CharReader &reader, Logger &logger,
return false;
}
+bool Number::parseFixedLenInt(CharReader &reader, Logger &logger, int base,
+ int len)
+{
+ char c;
+ reader.consumePeek();
+ for (int i = 0; i < len; i++) {
+ if (!reader.peek(c)) {
+ logger.error("Unexpected end of escape sequence", reader);
+ return false;
+ }
+ if (!appendChar(c, base, Number::Part::A, reader, logger)) {
+ return false;
+ }
+ reader.consumePeek();
+ }
+ return true;
+}
+
/* State machine states */
static const int STATE_INIT = 0;
@@ -535,10 +558,32 @@ static std::pair<bool, Variant> parseComplex(CharReader &reader, Logger &logger,
/* Class Reader */
+static bool encodeUtf8(std::stringstream &res, CharReader &reader,
+ Logger &logger, int64_t v, bool latin1)
+{
+ // Encode the unicode codepoint as UTF-8
+ uint32_t cp = static_cast<uint32_t>(v);
+ if (latin1 && cp > 0xFF) {
+ logger.error("Not a valid ISO-8859-1 (Latin-1) character, skipping", reader);
+ return false;
+ }
+
+ // Append the code point to the output stream
+ try {
+ utf8::append(cp, std::ostream_iterator<uint8_t>{res});
+ return true;
+ }
+ catch (utf8::invalid_code_point ex) {
+ logger.error("Invalid Unicode codepoint, skipping", reader);
+ }
+ return false;
+}
+
std::pair<bool, std::string> VariantReader::parseString(
CharReader &reader, Logger &logger, const std::unordered_set<char> *delims)
{
// Initialize the internal state
+ bool hadError = false;
int state = STATE_INIT;
char quote = 0;
std::stringstream res;
@@ -565,7 +610,7 @@ std::pair<bool, std::string> VariantReader::parseString(
case STATE_IN_STRING:
if (c == quote) {
reader.consumePeek();
- return std::make_pair(true, res.str());
+ return std::make_pair(!hadError, res.str());
} else if (c == '\\') {
state = STATE_ESCAPE;
reader.consumePeek();
@@ -608,17 +653,39 @@ std::pair<bool, std::string> VariantReader::parseString(
break;
case '\n':
break;
- case 'x':
- // TODO: Parse Latin-1 sequence hex XX
+ case 'x': {
+ // Parse Latin-1 sequence \xXX
+ Number n;
+ hadError =
+ !(n.parseFixedLenInt(reader, logger, 16, 2) &&
+ encodeUtf8(res, reader, logger, n.intValue(),
+ true)) ||
+ hadError;
break;
- case 'u':
- // TODO: Parse 16-Bit unicode character hex XXXX
+ }
+ case 'u': {
+ // Parse Unicode sequence \uXXXX
+ Number n;
+ hadError =
+ !(n.parseFixedLenInt(reader, logger, 16, 4) &&
+ encodeUtf8(res, reader, logger, n.intValue(),
+ false)) ||
+ hadError;
break;
+ }
default:
if (Utils::isNumeric(c)) {
- // TODO: Parse octal 000 sequence
+ // Parse Latin-1 sequence \000
+ reader.resetPeek();
+ Number n;
+ hadError =
+ !(n.parseFixedLenInt(reader, logger, 8, 3) &&
+ encodeUtf8(res, reader, logger, n.intValue(),
+ true)) ||
+ hadError;
} else {
logger.error(ERR_INVALID_ESCAPE, reader);
+ hadError = true;
}
break;
}
diff --git a/src/core/managed/Managed.hpp b/src/core/managed/Managed.hpp
index 4818c3d..8582702 100644
--- a/src/core/managed/Managed.hpp
+++ b/src/core/managed/Managed.hpp
@@ -19,7 +19,7 @@
#ifndef _OUSIA_MANAGED_HPP_
#define _OUSIA_MANAGED_HPP_
-#include "ManagedType.hpp"
+#include "Rtti.hpp"
#include "Manager.hpp"
namespace ousia {
@@ -108,25 +108,25 @@ public:
bool deleteData(const std::string &key);
/**
- * Returns the ManagedType instance registered for instances of the type
- * of this Managed instance.
+ * Returns the RttiBase instance registered for instances of the type of
+ * this Managed instance.
*
- * @return a reference to the registered ManagedType for this particular
+ * @return a reference to the registered RttiBase for this particular
* Managed class.
*/
- const ManagedType& type() const {
- return ManagedType::typeOf(typeid(*this));
+ const RttiBase &type() const
+ {
+ return typeOf(*this);
}
/**
- * Returns true if this Managed instance is of the given ManagedType.
+ * Returns true if this Managed instance is of the given RttiBase.
*
- * @param true if the ManagedType registered for this particular Managed
- * class is
+ * @param true if the RttiBase registered for this particular Managed
+ * class is of the given type or one of the registered parent types is of
+ * the given type.
*/
- bool isa(const ManagedType &t) const {
- return type().isa(t);
- }
+ bool isa(const RttiBase &t) const { return type().isa(t); }
};
/**
@@ -512,7 +512,6 @@ public:
*/
Managed *getOwner() const { return owner; }
};
-
}
#endif /* _OUSIA_MANAGED_HPP_ */
diff --git a/src/core/managed/ManagedType.hpp b/src/core/managed/ManagedType.hpp
deleted file mode 100644
index f3ed5fd..0000000
--- a/src/core/managed/ManagedType.hpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- Ousía
- Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
-
- This program 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 3 of the License, or
- (at your option) any later version.
-
- This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _OUSIA_MANAGED_TYPE_HPP_
-#define _OUSIA_MANAGED_TYPE_HPP_
-
-#include <typeinfo>
-#include <typeindex>
-#include <unordered_map>
-#include <unordered_set>
-
-namespace ousia {
-
-/**
- * The ManagedType is used to register type information that can be retrieved
- * using the "type" method of the Managed class.
- */
-class ManagedType {
-private:
- /**
- * Used internally to store all registered native types and their
- * corresponding type information.
- */
- static std::unordered_map<std::type_index, ManagedType *>& table() {
- static std::unordered_map<std::type_index, ManagedType *> table;
- return table;
- }
-
- /**
- * Name of the type -- for messages and debug output.
- */
- const std::string name;
-
- /**
- * Set containing references to the parent types.
- */
- const std::unordered_set<ManagedType *> parents;
-
-public:
- /**
- * ManagedType of no particular type.
- */
- static const ManagedType None;
-
- /**
- * Returns the ManagedType for the given type_info structure.
- */
- static const ManagedType &typeOf(const std::type_info &nativeType);
-
- /**
- * Default constructor. Creates a ManagedType instance with name "unknown"
- * and no parents.
- */
- ManagedType() : name("unknown") {}
-
- /**
- * Creates a new ManagedType instance and registers it in the global type
- * table.
- *
- * @param name is the name of the type.
- * @param nativeType is the underlying C++ class the type should be attached
- * to.
- */
- ManagedType(std::string name, const std::type_info &nativeType)
- : name(std::move(name))
- {
- table().emplace(std::make_pair(std::type_index{nativeType}, this));
- }
-
- /**
- * Creates a new ManagedType instance and registers it in the global type
- * table.
- *
- * @param name is the name of the type.
- * @param nativeType is the underlying C++ class the type should be attached
- * to.
- * @param parents is a list of parent types.
- */
- ManagedType(std::string name, const std::type_info &nativeType,
- std::unordered_set<ManagedType *> parents)
- : name(std::move(name)), parents(parents)
- {
- table().emplace(std::make_pair(std::type_index{nativeType}, this));
- }
-
- /**
- * Returns the name of this type.
- */
- std::string getName() const { return name; }
-
- /**
- * Returns true if this ManagedType instance is the given type or has the
- *given
- * type as one of its parents.
- *
- * @param other is the other type for which the relation to this type
- * should be checked.
- */
- bool isa(const ManagedType &other) const;
-};
-}
-
-#endif /* _OUSIA_MANAGED_TYPE_HPP_ */
-
diff --git a/src/core/managed/ManagedType.cpp b/src/core/managed/Rtti.cpp
index ed4c7da..eade524 100644
--- a/src/core/managed/ManagedType.cpp
+++ b/src/core/managed/Rtti.cpp
@@ -16,27 +16,39 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ManagedType.hpp"
+#include "Rtti.hpp"
namespace ousia {
-/* Instantiation of static variables */
+/* Class RttiStore */
-const ManagedType ManagedType::None;
+std::unordered_map<std::type_index, const RttiBase *> &RttiStore::table()
+{
+ static std::unordered_map<std::type_index, const RttiBase *> table;
+ return table;
+}
-/* Class ManagedType */
+void RttiStore::store(const std::type_info &native, const RttiBase *rtti)
+{
+ table().emplace(std::type_index{native}, rtti);
+}
-const ManagedType &ManagedType::typeOf(const std::type_info &nativeType)
+const RttiBase &RttiStore::lookup(const std::type_info &native)
{
- auto it = table().find(std::type_index{nativeType});
- if (it == table().end()) {
- return None;
+ const auto &tbl = table();
+ auto it = tbl.find(std::type_index{native});
+ if (it == tbl.end()) {
+ return RttiBase::None;
} else {
return *(it->second);
}
}
-bool ManagedType::isa(const ManagedType &other) const
+/* Class RttiBase */
+
+const RttiBase RttiBase::None;
+
+bool RttiBase::isa(const RttiBase &other) const
{
if (&other == this) {
return true;
@@ -48,5 +60,7 @@ bool ManagedType::isa(const ManagedType &other) const
}
return false;
}
+
+
}
diff --git a/src/core/managed/Rtti.hpp b/src/core/managed/Rtti.hpp
new file mode 100644
index 0000000..f53fd9b
--- /dev/null
+++ b/src/core/managed/Rtti.hpp
@@ -0,0 +1,183 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file Rtti.hpp
+ *
+ * Classes used for storing runtime type information (RTTI). RTTI is used to
+ * lookup objects in the object graph of a certain type and to attach
+ * information that should be accessible to the script engine.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_MANAGED_RTTI_HPP_
+#define _OUSIA_MANAGED_RTTI_HPP_
+
+#include <typeinfo>
+#include <typeindex>
+#include <unordered_map>
+#include <vector>
+
+namespace ousia {
+
+class RttiBase;
+
+/**
+ * Helper class used to globally store and access the runtime type information.
+ */
+class RttiStore {
+private:
+ /**
+ * Function used internally to access the static map storing all registered
+ * native types and their corresponding type information.
+ */
+ static std::unordered_map<std::type_index, const RttiBase *> &table();
+
+public:
+ /**
+ * Registers the given pointer to the RttiBase class in the RTTI table. Does
+ * not override information for already registered types.
+ *
+ * @param native is a reference at the native type information provided
+ * by the compiler.
+ * @param rtti is a pointer pointing at the type information that should be
+ * stored for this type.
+ */
+ static void store(const std::type_info &native, const RttiBase *rtti);
+
+ /**
+ * Looks up the type information stored for the given native type
+ * information.
+ */
+ static const RttiBase &lookup(const std::type_info &native);
+};
+
+/**
+ * The Rtti class allows for attaching data to native types that can be accessed
+ * at runtime. This type information can e.g. be retrieved using the "type"
+ * method of the Managed class. This system is used for attaching human readable
+ * names, parent types and script engine functionality. Use the Rtti class for
+ * convenient registration of type information.
+ */
+class RttiBase {
+private:
+ /**
+ * Set containing references to the parent types.
+ */
+ const std::vector<const RttiBase *> parents;
+
+public:
+ /**
+ * Rtti of no particular type.
+ */
+ static const RttiBase None;
+
+ /**
+ * Human readable name associated with the type.
+ */
+ const std::string name;
+
+ /**
+ * Default constructor. Creates a Rtti instance with name "unknown"
+ * and no parents.
+ */
+ RttiBase() : name("unknown") {}
+
+ /**
+ * Creates a new RttiBase instance and registers it in the global type
+ * table. Use the Rtti class for more convinient registration of type
+ * information.
+ *
+ * @param name is the name of the type.
+ * @param native is a reference at the native type information provided by
+ * the compiler.
+ * @param parents is a list of parent types.
+ */
+ RttiBase(std::string name, const std::type_info &native,
+ std::vector<const RttiBase *> parents =
+ std::vector<const RttiBase *>{})
+ : parents(std::move(parents)), name(std::move(name))
+ {
+ RttiStore::store(native, this);
+ }
+
+ /**
+ * Returns true if this Rtti instance is the given type or has the
+ * given type as one of its parents.
+ *
+ * @param other is the other type for which the relation to this type
+ * should be checked.
+ */
+ bool isa(const RttiBase &other) const;
+};
+
+/**
+ * The Rtti class allows for attaching data to native types that can be accessed
+ * at runtime. This type information can e.g. be retrieved using the "type"
+ * method of the Managed class. This system is used for attaching human
+ * readable names, parent types and script engine functionality.
+ *
+ * @tparam T is the class for which the type information should be registered.
+ */
+template <class T>
+class Rtti : public RttiBase {
+public:
+ /**
+ * Creates a new RttiBase instance and registers it in the global type
+ * table.
+ *
+ * @param name is the name of the type.
+ * @param parents is a list of parent types.
+ */
+ Rtti(std::string name, const std::vector<const RttiBase *> &parents =
+ std::vector<const RttiBase *>{})
+ : RttiBase(name, typeid(T), parents)
+ {
+ }
+};
+
+/**
+ * Function that can be used to retrieve the RTTI information of a Managed
+ * object.
+ *
+ * @tparam T is the C++ type for which the type information should be returned.
+ */
+template <typename T>
+inline const RttiBase &typeOf()
+{
+ return RttiStore::lookup(typeid(T));
+}
+
+/**
+ * Function that can be used to retrieve the RTTI information of a Managed
+ * object.
+ *
+ * @tparam T is the C++ type for which the type information should be returned.
+ * @param obj is a dummy object for which the type information should be
+ * returned.
+ */
+template <typename T>
+inline const RttiBase &typeOf(const T &obj)
+{
+ return RttiStore::lookup(typeid(obj));
+}
+}
+
+#endif /* _OUSIA_MANAGED_RTTI_HPP_ */
+
diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp
index f3c49dc..724bf0e 100644
--- a/src/core/model/Typesystem.cpp
+++ b/src/core/model/Typesystem.cpp
@@ -23,9 +23,42 @@
namespace ousia {
namespace model {
-EnumerationType EnumerationType::createValidated(
- Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values, Logger &logger)
+/* Class Type */
+
+bool Type::build(Variant &var, Logger &logger) const
+{
+ try {
+ return doBuild(var, logger);
+ }
+ catch (LoggableException ex) {
+ logger.log(ex);
+ var = create();
+ return false;
+ }
+}
+
+/* Class StringType */
+
+bool StringType::doBuild(Variant &var, Logger &logger) const
+{
+ if (!var.isPrimitive()) {
+ throw LoggableException{"Expected a string or primitive input."};
+ }
+
+ if (!var.isString()) {
+ logger.note(std::string("Implicit type conversion from ") +
+ var.getTypeName() + " to string.");
+ }
+ var = Variant{var.toString().c_str()};
+ return true;
+}
+
+/* Class EnumType */
+
+EnumType EnumType::createValidated(Manager &mgr, std::string name,
+ Handle<Typesystem> system,
+ const std::vector<std::string> &values,
+ Logger &logger)
{
std::map<std::string, size_t> unique_values;
for (size_t i = 0; i < values.size(); i++) {
@@ -38,8 +71,18 @@ EnumerationType EnumerationType::createValidated(
" was duplicated.");
}
}
- return std::move(EnumerationType(mgr, name, system, unique_values));
+ return std::move(EnumType(mgr, name, system, unique_values));
}
+
+/* RTTI type registrations */
+
+const Rtti<Type> Type_T("Type");
+const Rtti<StringType> StringType_T("StringType", {&Type_T});
+const Rtti<IntType> IntType_T("IntType", {&Type_T});
+const Rtti<DoubleType> DoubleType_T("DoubleType", {&Type_T});
+const Rtti<BoolType> BoolType_T("BoolType", {&Type_T});
+const Rtti<EnumType> EnumType_T("EnumType", {&Type_T});
+const Rtti<StructType> StructType_T("StructType", {&Type_T});
}
}
diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp
index 20c6e8b..c9793e2 100644
--- a/src/core/model/Typesystem.hpp
+++ b/src/core/model/Typesystem.hpp
@@ -19,7 +19,9 @@
/**
* @file Typesystem.hpp
*
- * TODO: Docu
+ * Contains the Entities described in a Typesystem. A Typesystem is a list
+ * of type descriptors, where a type is either primitive or a user defined
+ * type.
*
* @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
*/
@@ -40,79 +42,103 @@ namespace model {
class Typesystem;
+/**
+ * The abstract Type class represents a type descriptor. Each Type node is part
+ * of a Typesystem instance. Concrete instances of the Type class are immutable
+ * (they are guaranteed to represent exactly one type). Note that Type classes
+ * only contain the type description, instances of the Type class do not hold
+ * any data. Data is held by instances of the Variant class. How exactly the
+ * data is represented within the Variant instances is defined by the type
+ * definitions.
+ */
class Type : public Node {
protected:
+ /**
+ * Protected constructor to be called by the classes derived from the Type
+ * class.
+ *
+ * @param mgr is the Manager instance to be used for the Node.
+ * @param name is the name of the type.
+ * @param system is a reference to the parent TypeSystem instance.
+ * @param primitive is set to true for primitive types, such as ints,
+ * doubles, strings and enums.
+ */
Type(Manager &mgr, std::string name, Handle<Typesystem> system,
- bool inheritable, bool primitive)
- : Node(mgr, std::move(name), system),
- inheritable(inheritable),
- primitive(primitive)
+ bool primitive)
+ : Node(mgr, std::move(name), system), primitive(primitive)
{
}
- virtual bool doPrepare(Variant &var, Logger &log) const = 0;
-
-public:
/**
- * TODO: DOC
+ * Validates and completes the given variant. This pure virtual doBuild
+ * method must be overridden by derived classes. This function may throw
+ * an LoggableException in case the given data cannot be converted to
+ * the internal representation given by the type descriptor.
+ *
+ * @param var is a variant containing the data that should be checked and
+ * -- if possible and necessary -- converted to a variant adhering to the
+ * internal representation used by the Type class.
+ * @param logger is the Logger instance into which errors should be written.
+ * @return true if the conversion was successful, false otherwise.
*/
- const bool inheritable;
+ virtual bool doBuild(Variant &var, Logger &logger) const = 0;
+
+public:
/**
- * TODO: DOC
+ * Set to true, if this type descriptor is a primitive type.
*/
const bool primitive;
/**
- * TODO: DOC
+ * Pure virtual function which must construct a valid, default instance of
+ * the type that is being described by the typesystem.
*/
virtual Variant create() const = 0;
/**
- * TODO: DOC
+ * Validates and completes the given variant which was read from a
+ * user-supplied source.
+ *
+ * @param var is a variant containing the data that should be checked and
+ * -- if possible and necessary -- converted to a variant adhering to the
+ * internal representation used by the Type class.
+ * @param logger is the Logger instance into which errors should be written.
+ * @return true if the conversion was successful, false otherwise.
*/
- bool prepare(Variant &var, Logger &log) const
- {
- try {
- return doPrepare(var, log);
- }
- catch (LoggableException ex) {
- log.log(ex);
- var = create();
- return false;
- }
- }
+ bool build(Variant &var, Logger &logger) const;
};
+/**
+ * The StringType class represents the primitive string type. There should
+ * exactly be a single instance of this class available in a preloaded type
+ * system.
+ */
class StringType : public Type {
protected:
/**
- * TODO: DOC
+ * If possible, converts the given variant to a string. Only works, if the
+ * variant contains primitive objects (integers, strings, booleans, etc.).
*/
- bool doPrepare(Variant &var, Logger &log) const override
- {
- if (!var.isPrimitive()) {
- throw LoggableException{"Expected a string or primitive input."};
- }
-
- if (!var.isString()) {
- log.note(std::string("Implicit type conversion from ") +
- var.getTypeName() + " to string.");
- }
- var = Variant{var.toString().c_str()};
- return true;
- }
+ bool doBuild(Variant &var, Logger &logger) const override;
public:
/**
- * TODO: DOC
+ * Constructor of the StringType class. Only one instance of StringType
+ * should exist per project.
+ *
+ * @param mgr is the Manager instance to be used for the Node.
+ * @param name is the name of the type.
+ * @param system is a reference to the parent TypeSystem instance.
*/
StringType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "string", system, false, true)
+ : Type(mgr, "string", system, true)
{
}
/**
- * TODO: DOC
+ * Creates a variant containing an empty string.
+ *
+ * @return a variant containing an empty string.
*/
Variant create() const override { return Variant{""}; }
};
@@ -122,7 +148,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isInt()) {
throw LoggableException{"Expected an integer value."};
@@ -135,7 +161,7 @@ public:
* TODO: DOC
*/
IntType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "int", system, false, true)
+ : Type(mgr, "int", system, true)
{
}
@@ -150,7 +176,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isInt() && !var.isDouble()) {
throw LoggableException{"Expected a double value."};
@@ -164,7 +190,7 @@ public:
* TODO: DOC
*/
DoubleType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "double", system, false, true)
+ : Type(mgr, "double", system, true)
{
}
@@ -179,14 +205,14 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override { return true; }
+ bool doBuild(Variant &var, Logger &logger) const override { return true; }
public:
/**
* TODO: DOC
*/
UnknownType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "unknown", system, false, true)
+ : Type(mgr, "unknown", system, true)
{
}
@@ -201,7 +227,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isBool()) {
throw LoggableException("Expected boolean value!");
@@ -214,7 +240,7 @@ public:
* TODO: DOC
*/
BoolType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "bool", system, false, true)
+ : Type(mgr, "bool", system, true)
{
}
@@ -224,7 +250,7 @@ public:
Variant create() const override { return Variant{false}; }
};
-class EnumerationType : public Type {
+class EnumType : public Type {
private:
std::map<std::string, size_t> values;
@@ -232,7 +258,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (var.isInt()) {
int i = var.asInt();
@@ -245,10 +271,9 @@ protected:
return true;
}
- EnumerationType(Manager &mgr, std::string name, Handle<Typesystem> system,
- std::map<std::string, size_t> values)
- : Type(mgr, std::move(name), system, false, false),
- values(std::move(values))
+ EnumType(Manager &mgr, std::string name, Handle<Typesystem> system,
+ std::map<std::string, size_t> values)
+ : Type(mgr, std::move(name), system, false), values(std::move(values))
{
}
@@ -256,9 +281,9 @@ public:
/**
* TODO: DOC
*/
- EnumerationType(Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values)
- : Type(mgr, std::move(name), system, false, false)
+ EnumType(Manager &mgr, std::string name, Handle<Typesystem> system,
+ const std::vector<std::string> &values)
+ : Type(mgr, std::move(name), system, false)
{
for (size_t i = 0; i < values.size(); i++) {
this->values.insert(std::make_pair(values[i], i));
@@ -268,9 +293,10 @@ public:
/**
* TODO: DOC
*/
- static EnumerationType createValidated(
- Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values, Logger &logger);
+ static EnumType createValidated(Manager &mgr, std::string name,
+ Handle<Typesystem> system,
+ const std::vector<std::string> &values,
+ Logger &logger);
/**
* TODO: DOC
@@ -300,13 +326,13 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
// If we already have an array, we just check that.
- if(var.isArray()){
+ if (var.isArray()) {
auto arr = var.asArray();
- for(size_t a = 0; a < attrs.size(); a++){
- if(!attrs[a].type->prepare(arr[a], log)){
+ for (size_t a = 0; a < attrs.size(); a++) {
+ if (!attrs[a].type->build(arr[a], logger)) {
return false;
}
}
@@ -323,10 +349,10 @@ protected:
for (auto &a : attrs) {
auto it = map.find(a.name);
// we use the default if nothing is set.
- if (it == map.end() || !a.type->prepare(it->second, log)) {
- log.note(std::string("Using default value for ") + a.name);
+ if (it == map.end() || !a.type->build(it->second, logger)) {
+ logger.note(std::string("Using default value for ") + a.name);
vec.push_back(a.defaultValue);
- } else{
+ } else {
vec.push_back(it->second);
}
}
@@ -339,8 +365,7 @@ public:
StructType(Manager &mgr, std::string name, Handle<Typesystem> system,
std::vector<AttributeDescriptor> attrs)
- : Type(mgr, std::move(name), system, true, false),
- attrs(std::move(attrs))
+ : Type(mgr, std::move(name), system, false), attrs(std::move(attrs))
{
}
// TODO
@@ -360,14 +385,14 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isArray()) {
throw LoggableException("Expected array!");
}
bool res = true;
for (auto &v : var.asArray()) {
- if (!innerType->prepare(v, log)) {
+ if (!innerType->build(v, logger)) {
res = false;
}
}
@@ -381,7 +406,7 @@ public:
*/
ArrayType(Manager &mgr, std::string name, Handle<Typesystem> system,
Handle<Type> innerType)
- : Type(mgr, std::move(name), system, false, false),
+ : Type(mgr, std::move(name), system, false),
innerType(acquire(innerType))
{
}
diff --git a/test/core/common/VariantReaderTest.cpp b/test/core/common/VariantReaderTest.cpp
index 7972374..3d4e7bd 100644
--- a/test/core/common/VariantReaderTest.cpp
+++ b/test/core/common/VariantReaderTest.cpp
@@ -60,6 +60,71 @@ TEST(VariantReader, readString)
ASSERT_TRUE(res.first);
ASSERT_EQ("'\"\b\f\n\r\t\v", res.second);
}
+
+
+ // Hex Unicode character
+ {
+ CharReader reader("'linebreak\\u000A in unicode'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ("linebreak\n in unicode", res.second);
+ }
+}
+
+TEST(VariantReader, readStringUnicode)
+{
+ // Hex Unicode character
+ {
+ CharReader reader("'linebreak \\u000A in unicode'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ("linebreak \n in unicode", res.second);
+ }
+
+ // Hex Unicode character
+ {
+ CharReader reader("'hammer and sickle \\u262D in unicode'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ("hammer and sickle \342\230\255 in unicode", res.second);
+ }
+
+ // Octal Latin-1 character
+ {
+ CharReader reader("'copyright symbol \\251 in Unicode'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ("copyright symbol \302\251 in Unicode", res.second);
+ }
+
+ // Hexadecimal Latin-1 character
+ {
+ CharReader reader("'copyright symbol \\xA9 in Unicode'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ("copyright symbol \302\251 in Unicode", res.second);
+ }
+
+ // Errornous unicode escape sequence
+ {
+ CharReader reader("'\\uBLUB'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_FALSE(res.first);
+ }
+
+ // Errornous octal escape sequence
+ {
+ CharReader reader("'\\400'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_FALSE(res.first);
+ }
+
+ // Errornous hexadecimal latin1 escape sequence
+ {
+ CharReader reader("'\\xa'");
+ auto res = VariantReader::parseString(reader, logger, {';'});
+ ASSERT_FALSE(res.first);
+ }
}
TEST(VariantReader, parseUnescapedString)
diff --git a/test/core/managed/ManagedTest.cpp b/test/core/managed/ManagedTest.cpp
index f196770..c88cf7a 100644
--- a/test/core/managed/ManagedTest.cpp
+++ b/test/core/managed/ManagedTest.cpp
@@ -75,33 +75,10 @@ class TypeTestManaged5 : public Managed {
using Managed::Managed;
};
-ManagedType Type1("Type1", typeid(TypeTestManaged1));
-ManagedType Type2("Type2", typeid(TypeTestManaged2));
-ManagedType Type3("Type3", typeid(TypeTestManaged3), {&Type1});
-ManagedType Type4("Type2", typeid(TypeTestManaged4), {&Type3, &Type2});
-
-TEST(ManagedType, isa)
-{
- ASSERT_TRUE(Type1.isa(Type1));
- ASSERT_FALSE(Type1.isa(Type2));
- ASSERT_FALSE(Type1.isa(Type3));
- ASSERT_FALSE(Type1.isa(Type4));
-
- ASSERT_FALSE(Type2.isa(Type1));
- ASSERT_TRUE(Type2.isa(Type2));
- ASSERT_FALSE(Type2.isa(Type3));
- ASSERT_FALSE(Type2.isa(Type4));
-
- ASSERT_TRUE(Type3.isa(Type1));
- ASSERT_FALSE(Type3.isa(Type2));
- ASSERT_TRUE(Type3.isa(Type3));
- ASSERT_FALSE(Type3.isa(Type4));
-
- ASSERT_TRUE(Type4.isa(Type1));
- ASSERT_TRUE(Type4.isa(Type2));
- ASSERT_TRUE(Type4.isa(Type3));
- ASSERT_TRUE(Type4.isa(Type4));
-}
+static const Rtti<TypeTestManaged1> Type1("Type1");
+static const Rtti<TypeTestManaged2> Type2("Type2");
+static const Rtti<TypeTestManaged3> Type3("Type3", {&Type1});
+static const Rtti<TypeTestManaged4> Type4("Type4", {&Type3, &Type2});
TEST(Managed, type)
{
@@ -117,7 +94,10 @@ TEST(Managed, type)
ASSERT_EQ(&Type2, &m2->type());
ASSERT_EQ(&Type3, &m3->type());
ASSERT_EQ(&Type4, &m4->type());
- ASSERT_EQ(&ManagedType::None, &m5->type());
+ ASSERT_EQ(&RttiBase::None, &m5->type());
+
+ ASSERT_EQ(&Type1, &typeOf<TypeTestManaged1>());
+ ASSERT_EQ(&Type1, &typeOf(*m1));
}
}
diff --git a/test/core/managed/RttiTest.cpp b/test/core/managed/RttiTest.cpp
new file mode 100644
index 0000000..091bdea
--- /dev/null
+++ b/test/core/managed/RttiTest.cpp
@@ -0,0 +1,63 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <array>
+#include <string>
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <core/managed/Rtti.hpp>
+
+namespace ousia {
+
+class RttiTestClass1 {};
+class RttiTestClass2 {};
+class RttiTestClass3 {};
+class RttiTestClass4 {};
+
+static const Rtti<RttiTestClass1> Type1("Type1");
+static const Rtti<RttiTestClass2> Type2("Type2");
+static const Rtti<RttiTestClass3> Type3("Type3", {&Type1});
+static const Rtti<RttiTestClass4> Type4("Type4", {&Type3, &Type2});
+
+TEST(Rtti, isa)
+{
+ ASSERT_TRUE(Type1.isa(Type1));
+ ASSERT_FALSE(Type1.isa(Type2));
+ ASSERT_FALSE(Type1.isa(Type3));
+ ASSERT_FALSE(Type1.isa(Type4));
+
+ ASSERT_FALSE(Type2.isa(Type1));
+ ASSERT_TRUE(Type2.isa(Type2));
+ ASSERT_FALSE(Type2.isa(Type3));
+ ASSERT_FALSE(Type2.isa(Type4));
+
+ ASSERT_TRUE(Type3.isa(Type1));
+ ASSERT_FALSE(Type3.isa(Type2));
+ ASSERT_TRUE(Type3.isa(Type3));
+ ASSERT_FALSE(Type3.isa(Type4));
+
+ ASSERT_TRUE(Type4.isa(Type1));
+ ASSERT_TRUE(Type4.isa(Type2));
+ ASSERT_TRUE(Type4.isa(Type3));
+ ASSERT_TRUE(Type4.isa(Type4));
+}
+
+}
+
diff --git a/test/core/model/TypesystemTest.cpp b/test/core/model/TypesystemTest.cpp
new file mode 100644
index 0000000..9939adf
--- /dev/null
+++ b/test/core/model/TypesystemTest.cpp
@@ -0,0 +1,104 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+
+#include <core/model/Typesystem.hpp>
+
+namespace ousia {
+namespace model {
+
+TEST(Type, rtti)
+{
+ Manager mgr(1);
+ Rooted<StringType> strType{new StringType(mgr, nullptr)};
+
+ ASSERT_TRUE(typeOf(*strType).isa(typeOf<Type>()));
+}
+
+TEST(StringType, creation)
+{
+ Manager mgr(1);
+ Rooted<StringType> strType{new StringType(mgr, nullptr)};
+
+ Variant val = strType->create();
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("", val.asString());
+}
+
+TEST(StringType, conversion)
+{
+ Logger logger;
+ Manager mgr(1);
+ Rooted<StringType> strType{new StringType(mgr, nullptr)};
+
+ {
+ Variant val{42};
+ ASSERT_TRUE(strType->build(val, logger));
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("42", val.asString());
+ }
+
+ {
+ Variant val{42.5};
+ ASSERT_TRUE(strType->build(val, logger));
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("42.5", val.asString());
+ }
+
+ {
+ Variant val{true};
+ ASSERT_TRUE(strType->build(val, logger));
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("true", val.asString());
+ }
+
+ {
+ Variant val{false};
+ ASSERT_TRUE(strType->build(val, logger));
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("false", val.asString());
+ }
+
+ {
+ Variant val{nullptr};
+ ASSERT_TRUE(strType->build(val, logger));
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("null", val.asString());
+ }
+
+ {
+ Variant val{"test"};
+ ASSERT_TRUE(strType->build(val, logger));
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("test", val.asString());
+ }
+
+ {
+ Variant val{{1, 2, true, false}};
+ ASSERT_FALSE(strType->build(val, logger));
+ ASSERT_TRUE(val.isString());
+ ASSERT_EQ("", val.asString());
+ }
+
+}
+
+}
+}