Commit 237d2f2e authored by John Stiles's avatar John Stiles

Merge remote-tracking branch 'miloyip/master'

parents 26e089b9 a1fac159
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
...@@ -8,7 +8,7 @@ In RapidJSON, `Reader` (typedef of `GenericReader<...>`) is the SAX-style parser ...@@ -8,7 +8,7 @@ In RapidJSON, `Reader` (typedef of `GenericReader<...>`) is the SAX-style parser
# Reader {#Reader} # Reader {#Reader}
`Reader` parses a JSON from a stream. While it reads characters from the stream, it analyze the characters according to the syntax of JSON, and publish events to a handler. `Reader` parses a JSON from a stream. While it reads characters from the stream, it analyzes the characters according to the syntax of JSON, and publishes events to a handler.
For example, here is a JSON. For example, here is a JSON.
...@@ -24,7 +24,7 @@ For example, here is a JSON. ...@@ -24,7 +24,7 @@ For example, here is a JSON.
} }
~~~~~~~~~~ ~~~~~~~~~~
While a `Reader` parses this JSON, it publishes the following events to the handler sequentially: When a `Reader` parses this JSON, it publishes the following events to the handler sequentially:
~~~~~~~~~~ ~~~~~~~~~~
StartObject() StartObject()
...@@ -50,7 +50,7 @@ EndArray(4) ...@@ -50,7 +50,7 @@ EndArray(4)
EndObject(7) EndObject(7)
~~~~~~~~~~ ~~~~~~~~~~
These events can be easily matched with the JSON, except some event parameters need further explanation. Let's see the `simplereader` example which produces exactly the same output as above: These events can be easily matched with the JSON, but some event parameters need further explanation. Let's see the `simplereader` example which produces exactly the same output as above:
~~~~~~~~~~cpp ~~~~~~~~~~cpp
#include "rapidjson/reader.h" #include "rapidjson/reader.h"
...@@ -91,11 +91,11 @@ void main() { ...@@ -91,11 +91,11 @@ void main() {
} }
~~~~~~~~~~ ~~~~~~~~~~
Note that, RapidJSON uses template to statically bind the `Reader` type and the handler type, instead of using class with virtual functions. This paradigm can improve the performance by inlining functions. Note that RapidJSON uses templates to statically bind the `Reader` type and the handler type, instead of using classes with virtual functions. This paradigm can improve performance by inlining functions.
## Handler {#Handler} ## Handler {#Handler}
As the previous example showed, user needs to implement a handler, which consumes the events (function calls) from `Reader`. The handler must contain the following member functions. As shown in the previous example, the user needs to implement a handler which consumes the events (via function calls) from the `Reader`. The handler must contain the following member functions.
~~~~~~~~~~cpp ~~~~~~~~~~cpp
class Handler { class Handler {
...@@ -122,15 +122,15 @@ class Handler { ...@@ -122,15 +122,15 @@ class Handler {
When the `Reader` encounters a JSON number, it chooses a suitable C++ type mapping. And then it calls *one* function out of `Int(int)`, `Uint(unsigned)`, `Int64(int64_t)`, `Uint64(uint64_t)` and `Double(double)`. If `kParseNumbersAsStrings` is enabled, `Reader` will always calls `RawNumber()` instead. When the `Reader` encounters a JSON number, it chooses a suitable C++ type mapping. And then it calls *one* function out of `Int(int)`, `Uint(unsigned)`, `Int64(int64_t)`, `Uint64(uint64_t)` and `Double(double)`. If `kParseNumbersAsStrings` is enabled, `Reader` will always calls `RawNumber()` instead.
`String(const char* str, SizeType length, bool copy)` is called when the `Reader` encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character `\0` inside a string. If such situation happens, `strlen(str) < length`. The last `copy` indicates whether the handler needs to make a copy of the string. For normal parsing, `copy = true`. Only when *insitu* parsing is used, `copy = false`. And beware that, the character type depends on the target encoding, which will be explained later. `String(const char* str, SizeType length, bool copy)` is called when the `Reader` encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character `\0` inside a string. If such situation happens, `strlen(str) < length`. The last `copy` indicates whether the handler needs to make a copy of the string. For normal parsing, `copy = true`. Only when *insitu* parsing is used, `copy = false`. And be aware that the character type depends on the target encoding, which will be explained later.
When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeats until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler, user may not need this parameter. When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeat until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler; users who do not need this parameter may ignore it.
Array is similar to object but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler. Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler.
Every handler functions returns a `bool`. Normally it should returns `true`. If the handler encounters an error, it can return `false` to notify event publisher to stop further processing. Every handler function returns a `bool`. Normally it should return `true`. If the handler encounters an error, it can return `false` to notify the event publisher to stop further processing.
For example, when we parse a JSON with `Reader` and the handler detected that the JSON does not conform to the required schema, then the handler can return `false` and let the `Reader` stop further parsing. And the `Reader` will be in error state with error code `kParseErrorTermination`. For example, when we parse a JSON with `Reader` and the handler detects that the JSON does not conform to the required schema, the handler can return `false` and let the `Reader` stop further parsing. This will place the `Reader` in an error state, with error code `kParseErrorTermination`.
## GenericReader {#GenericReader} ## GenericReader {#GenericReader}
...@@ -149,19 +149,19 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader; ...@@ -149,19 +149,19 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
} // namespace rapidjson } // namespace rapidjson
~~~~~~~~~~ ~~~~~~~~~~
The `Reader` uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the `str` parameter in `String()` calls. For example, to parse a UTF-8 stream and outputs UTF-16 string events, you can define a reader by: The `Reader` uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the `str` parameter in `String()` calls. For example, to parse a UTF-8 stream and output UTF-16 string events, you can define a reader by:
~~~~~~~~~~cpp ~~~~~~~~~~cpp
GenericReader<UTF8<>, UTF16<> > reader; GenericReader<UTF8<>, UTF16<> > reader;
~~~~~~~~~~ ~~~~~~~~~~
Note that, the default character type of `UTF16` is `wchar_t`. So this `reader`needs to call `String(const wchar_t*, SizeType, bool)` of the handler. Note that, the default character type of `UTF16` is `wchar_t`. So this `reader` needs to call `String(const wchar_t*, SizeType, bool)` of the handler.
The third template parameter `Allocator` is the allocator type for internal data structure (actually a stack). The third template parameter `Allocator` is the allocator type for internal data structure (actually a stack).
## Parsing {#SaxParsing} ## Parsing {#SaxParsing}
The one and only one function of `Reader` is to parse JSON. The main function of `Reader` is used to parse JSON.
~~~~~~~~~~cpp ~~~~~~~~~~cpp
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
...@@ -172,7 +172,30 @@ template <typename InputStream, typename Handler> ...@@ -172,7 +172,30 @@ template <typename InputStream, typename Handler>
bool Parse(InputStream& is, Handler& handler); bool Parse(InputStream& is, Handler& handler);
~~~~~~~~~~ ~~~~~~~~~~
If an error occurs during parsing, it will return `false`. User can also calls `bool HasParseEror()`, `ParseErrorCode GetParseErrorCode()` and `size_t GetErrorOffset()` to obtain the error states. Actually `Document` uses these `Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) for details about parse error. If an error occurs during parsing, it will return `false`. User can also call `bool HasParseError()`, `ParseErrorCode GetParseErrorCode()` and `size_t GetErrorOffset()` to obtain the error states. In fact, `Document` uses these `Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) for details about parse errors.
## Token-by-Token Parsing {#TokenByTokenParsing}
Some users may wish to parse a JSON input stream a single token at a time, instead of immediately parsing an entire document without stopping. To parse JSON this way, instead of calling `Parse`, you can use the `IterativeParse` set of functions:
~~~~~~~~~~cpp
void IterativeParseInit();
template <unsigned parseFlags, typename InputStream, typename Handler>
bool IterativeParseNext(InputStream& is, Handler& handler);
bool IterativeParseComplete();
~~~~~~~~~~
Here is an example of iteratively parsing JSON, token by token:
~~~~~~~~~~cpp
reader.IterativeParseInit();
while (!reader.IterativeParseComplete()) {
reader.IterativeParseNext<kParseDefaultFlags>(is, handler);
// Your handler has been called once.
}
~~~~~~~~~~
# Writer {#Writer} # Writer {#Writer}
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_
#include "../stream.h" #include "../stream.h"
#include <cwchar>
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
...@@ -34,6 +35,16 @@ inline SizeType StrLen(const Ch* s) { ...@@ -34,6 +35,16 @@ inline SizeType StrLen(const Ch* s) {
return SizeType(p - s); return SizeType(p - s);
} }
template <>
inline SizeType StrLen(const char* s) {
return SizeType(std::strlen(s));
}
template <>
inline SizeType StrLen(const wchar_t* s) {
return SizeType(std::wcslen(s));
}
//! Returns number of code points in a encoded string. //! Returns number of code points in a encoded string.
template<typename Encoding> template<typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
......
...@@ -107,7 +107,8 @@ public: ...@@ -107,7 +107,8 @@ public:
return Base::WriteString(str, length); return Base::WriteString(str, length);
} }
bool String(const Ch* str, SizeType length, bool copy = false) { template <typename T>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0); RAPIDJSON_ASSERT(str != 0);
(void)copy; (void)copy;
PrettyPrefix(kStringType); PrettyPrefix(kStringType);
...@@ -126,7 +127,8 @@ public: ...@@ -126,7 +127,8 @@ public:
return Base::WriteStartObject(); return Base::WriteStartObject();
} }
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } template <typename T>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T* str, SizeType length, bool copy = false) { return String(str, length, copy); }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool Key(const std::basic_string<Ch>& str) { bool Key(const std::basic_string<Ch>& str) {
...@@ -136,8 +138,10 @@ public: ...@@ -136,8 +138,10 @@ public:
bool EndObject(SizeType memberCount = 0) { bool EndObject(SizeType memberCount = 0) {
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) { if (!empty) {
...@@ -182,8 +186,22 @@ public: ...@@ -182,8 +186,22 @@ public:
//@{ //@{
//! Simpler but slower overload. //! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); } template <typename T>
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T* const& str) { return String(str, internal::StrLen(str)); }
template <typename T>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T* const& str) { return Key(str, internal::StrLen(str)); }
//! The compiler can give us the length of quoted strings for free.
template <typename T, size_t N>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T (&str)[N]) {
RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated)
return String(str, N-1);
}
template <typename T, size_t N>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T (&str)[N]) {
RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated)
return Key(str, N-1);
}
//@} //@}
......
...@@ -1928,7 +1928,7 @@ private: ...@@ -1928,7 +1928,7 @@ private:
const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); } const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
OutputHandler& CreateNullHandler() { OutputHandler& CreateNullHandler() {
return *(nullHandler_ = static_cast<OutputHandler*>(GetStateAllocator().Malloc(sizeof(OutputHandler)))); return *(nullHandler_ = new (GetStateAllocator().Malloc(sizeof(OutputHandler))) OutputHandler);
} }
static const size_t kDefaultSchemaStackCapacity = 1024; static const size_t kDefaultSchemaStackCapacity = 1024;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_
#include "stream.h" #include "stream.h"
#include "internal/meta.h"
#include "internal/stack.h" #include "internal/stack.h"
#include "internal/strfunc.h" #include "internal/strfunc.h"
#include "internal/dtoa.h" #include "internal/dtoa.h"
...@@ -198,7 +199,8 @@ public: ...@@ -198,7 +199,8 @@ public:
return EndValue(WriteString(str, length)); return EndValue(WriteString(str, length));
} }
bool String(const Ch* str, SizeType length, bool copy = false) { template <typename T>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0); RAPIDJSON_ASSERT(str != 0);
(void)copy; (void)copy;
Prefix(kStringType); Prefix(kStringType);
...@@ -217,12 +219,14 @@ public: ...@@ -217,12 +219,14 @@ public:
return WriteStartObject(); return WriteStartObject();
} }
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } template <typename T>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T* str, SizeType length, bool copy = false) { return String(str, length, copy); }
bool EndObject(SizeType memberCount = 0) { bool EndObject(SizeType memberCount = 0) {
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
level_stack_.template Pop<Level>(1); level_stack_.template Pop<Level>(1);
return EndValue(WriteEndObject()); return EndValue(WriteEndObject());
} }
...@@ -246,8 +250,22 @@ public: ...@@ -246,8 +250,22 @@ public:
//@{ //@{
//! Simpler but slower overload. //! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); } template <typename T>
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T* const& str) { return String(str, internal::StrLen(str)); }
template <typename T>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T* const& str) { return Key(str, internal::StrLen(str)); }
//! The compiler can give us the length of quoted strings for free.
template <typename T, size_t N>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T (&str)[N]) {
RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated)
return String(str, N-1);
}
template <typename T, size_t N>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T (&str)[N]) {
RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated)
return Key(str, N-1);
}
//@} //@}
......
...@@ -79,7 +79,7 @@ add_test(NAME unittest ...@@ -79,7 +79,7 @@ add_test(NAME unittest
if(NOT MSVC) if(NOT MSVC)
# Not running SIMD.* unit test cases for Valgrind # Not running SIMD.* unit test cases for Valgrind
add_test(NAME valgrind_unittest add_test(NAME valgrind_unittest
COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.* COMMAND valgrind --suppressions=${CMAKE_SOURCE_DIR}/test/valgrind.supp --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.*
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")
......
...@@ -207,6 +207,57 @@ TEST(PrettyWriter, RawValue) { ...@@ -207,6 +207,57 @@ TEST(PrettyWriter, RawValue) {
buffer.GetString()); buffer.GetString());
} }
TEST(PrettyWriter, InvalidEventSequence) {
// {]
{
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
writer.StartObject();
EXPECT_THROW(writer.EndArray(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
// [}
{
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
writer.StartArray();
EXPECT_THROW(writer.EndObject(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
// { 1:
{
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
writer.StartObject();
EXPECT_THROW(writer.Int(1), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
// { 'a' }
{
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("a");
EXPECT_THROW(writer.EndObject(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
// { 'a':'b','c' }
{
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("a");
writer.String("b");
writer.Key("c");
EXPECT_THROW(writer.EndObject(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
static PrettyWriter<StringBuffer> WriterGen(StringBuffer &target) { static PrettyWriter<StringBuffer> WriterGen(StringBuffer &target) {
......
...@@ -1281,6 +1281,12 @@ TEST(SchemaValidatingWriter, Simple) { ...@@ -1281,6 +1281,12 @@ TEST(SchemaValidatingWriter, Simple) {
EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType("")); EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
} }
TEST(Schema, Issue848) {
rapidjson::Document d;
rapidjson::SchemaDocument s(d);
rapidjson::GenericSchemaValidator<rapidjson::SchemaDocument, rapidjson::Document> v(s);
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
static SchemaDocument ReturnSchemaDocument() { static SchemaDocument ReturnSchemaDocument() {
......
...@@ -442,6 +442,28 @@ TEST(Writer, InvalidEventSequence) { ...@@ -442,6 +442,28 @@ TEST(Writer, InvalidEventSequence) {
EXPECT_THROW(writer.Int(1), AssertException); EXPECT_THROW(writer.Int(1), AssertException);
EXPECT_FALSE(writer.IsComplete()); EXPECT_FALSE(writer.IsComplete());
} }
// { 'a' }
{
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("a");
EXPECT_THROW(writer.EndObject(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
// { 'a':'b','c' }
{
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("a");
writer.String("b");
writer.Key("c");
EXPECT_THROW(writer.EndObject(), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
} }
TEST(Writer, NaN) { TEST(Writer, NaN) {
......
{
Suppress wcslen valgrind report 1
Memcheck:Cond
fun:__wcslen_sse2
}
{
Suppress wcslen valgrind report 2
Memcheck:Addr8
fun:__wcslen_sse2
}
{
Suppress wcslen valgrind report 3
Memcheck:Value8
fun:__wcslen_sse2
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment