Skip to content

Commit

Permalink
Merge branch 'develop' into feature/emplace
Browse files Browse the repository at this point in the history
  • Loading branch information
nlohmann committed Nov 28, 2016
2 parents 693bfe4 + a791af3 commit 6ecff31
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 136 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ doc/html
me.nlohmann.json.docset

benchmarks/files/numbers/*.json

.idea
cmake-build-debug

8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,22 +84,22 @@ matrix:
# Coverity (only for branch coverity_scan)

- os: linux
compiler: gcc
compiler: clang
before_install: echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5', 'valgrind']
packages: ['valgrind']
coverity_scan:
project:
name: "nlohmann/json"
description: "Build submitted via Travis CI"
notification_email: niels.lohmann@gmail.com
build_command_prepend: "make clean ; sudo cp $(which g++-5) $(which g++)"
build_command_prepend: "make clean"
build_command: "make"
branch_pattern: coverity_scan
env:
- COMPILER=g++-5
- LLVM_VERSION=3.6.0
- SPECIAL=coverity

# OSX / Clang
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pretty:
# benchmarks
json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/cxxopts.hpp src/json.hpp
cd benchmarks/files/numbers ; python generate.py
$(CXX) -std=c++11 $(CXXFLAGS) -DNDEBUG -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@
$(CXX) -std=c++11 -pthread $(CXXFLAGS) -DNDEBUG -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@
./json_benchmarks


Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json)
[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json)
[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/fsf5FqYe6GoX68W6)
[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
Expand Down Expand Up @@ -499,6 +500,9 @@ I deeply appreciate the help of the following people.
- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable.
- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](http://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling.
- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.

Thanks a lot for helping out!

Expand Down
173 changes: 92 additions & 81 deletions benchmarks/benchmarks.cpp
Original file line number Diff line number Diff line change
@@ -1,107 +1,118 @@
#define BENCHPRESS_CONFIG_MAIN

#include <fstream>
#include <sstream>
#include <benchpress.hpp>
#include <json.hpp>
#include <pthread.h>
#include <thread>

BENCHMARK("parse jeopardy.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json");
nlohmann::json j;
j << input_file;
}
})
using json = nlohmann::json;

BENCHMARK("parse canada.json", [](benchpress::context* ctx)
struct StartUp
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
StartUp()
{
std::ifstream input_file("benchmarks/files/nativejson-benchmark/canada.json");
nlohmann::json j;
j << input_file;
#ifndef __llvm__
// pin thread to a single CPU
cpu_set_t cpuset;
pthread_t thread;
thread = pthread_self();
CPU_ZERO(&cpuset);
CPU_SET(std::thread::hardware_concurrency() - 1, &cpuset);
pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
#endif
}
})
};
StartUp startup;

BENCHMARK("parse citm_catalog.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
std::ifstream input_file("benchmarks/files/nativejson-benchmark/citm_catalog.json");
nlohmann::json j;
j << input_file;
}
})
enum class EMode { input, output_no_indent, output_with_indent };

BENCHMARK("parse twitter.json", [](benchpress::context* ctx)
static void bench(benchpress::context& ctx,
const std::string& in_path,
const EMode mode)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
// using string streams for benchmarking to factor-out cold-cache disk
// access.
std::stringstream istr;
{
std::ifstream input_file("benchmarks/files/nativejson-benchmark/twitter.json");
nlohmann::json j;
j << input_file;
}
})
// read file into string stream
std::ifstream input_file(in_path);
istr << input_file.rdbuf();
input_file.close();

BENCHMARK("parse numbers/floats.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
std::ifstream input_file("benchmarks/files/numbers/floats.json");
nlohmann::json j;
j << input_file;
// read the stream once
json j;
j << istr;
// clear flags and rewind
istr.clear();
istr.seekg(0);
}
})

BENCHMARK("parse numbers/signed_ints.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
switch (mode)
{
std::ifstream input_file("benchmarks/files/numbers/signed_ints.json");
nlohmann::json j;
j << input_file;
}
})
// benchmarking input
case EMode::input:
{
ctx.reset_timer();

BENCHMARK("parse numbers/unsigned_ints.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
std::ifstream input_file("benchmarks/files/numbers/unsigned_ints.json");
nlohmann::json j;
j << input_file;
}
})
for (size_t i = 0; i < ctx.num_iterations(); ++i)
{
// clear flags and rewind
istr.clear();
istr.seekg(0);
json j;
j << istr;
}

BENCHMARK("dump jeopardy.json", [](benchpress::context* ctx)
{
std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json");
nlohmann::json j;
j << input_file;
std::ofstream output_file("jeopardy.dump.json");
break;
}

ctx->reset_timer();
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
output_file << j;
}
// benchmarking output
case EMode::output_no_indent:
case EMode::output_with_indent:
{
// create JSON value from input
json j;
j << istr;
std::stringstream ostr;

std::remove("jeopardy.dump.json");
})
ctx.reset_timer();
for (size_t i = 0; i < ctx.num_iterations(); ++i)
{
if (mode == EMode::output_no_indent)
{
ostr << j;
}
else
{
ostr << std::setw(4) << j;
}

BENCHMARK("dump jeopardy.json with indent", [](benchpress::context* ctx)
{
std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json");
nlohmann::json j;
j << input_file;
std::ofstream output_file("jeopardy.dump.json");
// reset data
ostr.str(std::string());
}

ctx->reset_timer();
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
output_file << std::setw(4) << j;
break;
}
}
}

#define BENCHMARK_I(mode, title, in_path) \
BENCHMARK((title), [](benchpress::context* ctx) \
{ \
bench(*ctx, (in_path), (mode)); \
})

BENCHMARK_I(EMode::input, "parse jeopardy.json", "benchmarks/files/jeopardy/jeopardy.json");
BENCHMARK_I(EMode::input, "parse canada.json", "benchmarks/files/nativejson-benchmark/canada.json");
BENCHMARK_I(EMode::input, "parse citm_catalog.json", "benchmarks/files/nativejson-benchmark/citm_catalog.json");
BENCHMARK_I(EMode::input, "parse twitter.json", "benchmarks/files/nativejson-benchmark/twitter.json");
BENCHMARK_I(EMode::input, "parse numbers/floats.json", "benchmarks/files/numbers/floats.json");
BENCHMARK_I(EMode::input, "parse numbers/signed_ints.json", "benchmarks/files/numbers/signed_ints.json");
BENCHMARK_I(EMode::input, "parse numbers/unsigned_ints.json", "benchmarks/files/numbers/unsigned_ints.json");

std::remove("jeopardy.dump.json");
})
BENCHMARK_I(EMode::output_no_indent, "dump jeopardy.json", "benchmarks/files/jeopardy/jeopardy.json");
BENCHMARK_I(EMode::output_with_indent, "dump jeopardy.json with indent", "benchmarks/files/jeopardy/jeopardy.json");
BENCHMARK_I(EMode::output_no_indent, "dump numbers/floats.json", "benchmarks/files/numbers/floats.json");
BENCHMARK_I(EMode::output_no_indent, "dump numbers/signed_ints.json", "benchmarks/files/numbers/signed_ints.json");
39 changes: 14 additions & 25 deletions src/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ SOFTWARE.
#include <iostream> // istream, ostream
#include <iterator> // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
#include <limits> // numeric_limits
#include <locale> // locale, numpunct
#include <locale> // locale
#include <map> // map
#include <memory> // addressof, allocator, allocator_traits, unique_ptr
#include <numeric> // accumulate
Expand Down Expand Up @@ -122,26 +122,6 @@ struct has_mapped_type
std::is_integral<decltype(detect(std::declval<T>()))>::value;
};

/*!
@brief helper class to create locales with decimal point
This struct is used a default locale during the JSON serialization. JSON
requires the decimal point to be `.`, so this function overloads the
`do_decimal_point()` function to return `.`. This function is called by
float-to-string conversions to retrieve the decimal separator between integer
and fractional parts.
@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
@since version 2.0.0
*/
struct DecimalSeparator : std::numpunct<char>
{
char do_decimal_point() const
{
return '.';
}
};

}

/*!
Expand Down Expand Up @@ -2201,8 +2181,7 @@ class basic_json
{
std::stringstream ss;
// fix locale problems
const static std::locale loc(std::locale(), new DecimalSeparator);
ss.imbue(loc);
ss.imbue(std::locale::classic());

// 6, 15 or 16 digits of precision allows round-trip IEEE 754
// string->float->string, string->double->string or string->long
Expand Down Expand Up @@ -5913,7 +5892,7 @@ class basic_json
o.width(0);

// fix locale problems
const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
const auto old_locale = o.imbue(std::locale::classic());
// set precision

// 6, 15 or 16 digits of precision allows round-trip IEEE 754
Expand Down Expand Up @@ -7702,6 +7681,12 @@ class basic_json
explicit lexer(std::istream& s)
: m_stream(&s), m_line_buffer()
{
// immediately abort if stream is erroneous
if (s.fail())
{
throw std::invalid_argument("stream error: " + std::string(strerror(errno)));
}

// fill buffer
fill_line_buffer();

Expand Down Expand Up @@ -8841,14 +8826,18 @@ class basic_json
m_line_buffer.clear();
for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor)
{
assert(m_cursor != nullptr);
m_line_buffer.append(1, static_cast<const char>(*m_cursor));
}
}

// append n characters to make sure that there is sufficient
// space between m_cursor and m_limit
m_line_buffer.append(1, '\x00');
m_line_buffer.append(n - 1, '\x01');
if (n > 0)
{
m_line_buffer.append(n - 1, '\x01');
}
}
else
{
Expand Down
Loading

0 comments on commit 6ecff31

Please sign in to comment.