Skip to content

Commit 3ce8419

Browse files
committed
try_as_double, try_as_integer
1 parent ba2acb1 commit 3ce8419

File tree

4 files changed

+86
-26
lines changed

4 files changed

+86
-26
lines changed

include/jsoncons/basic_json.hpp

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include <jsoncons/allocator_set.hpp>
2828
#include <jsoncons/config/compiler_support.hpp>
2929
#include <jsoncons/config/version.hpp>
30+
#include <jsoncons/conv_error.hpp>
31+
#include <jsoncons/conversion_result.hpp>
3032
#include <jsoncons/json_array.hpp>
3133
#include <jsoncons/json_decoder.hpp>
3234
#include <jsoncons/json_encoder.hpp>
@@ -395,7 +397,6 @@ namespace jsoncons {
395397
using allocator_type = Allocator;
396398

397399
using policy_type = Policy;
398-
399400
using char_type = CharT;
400401
using char_traits_type = std::char_traits<char_type>;
401402
using string_view_type = jsoncons::basic_string_view<char_type,char_traits_type>;
@@ -3371,8 +3372,10 @@ namespace jsoncons {
33713372
}
33723373

33733374
template <typename IntegerType>
3374-
IntegerType as_integer() const
3375+
conversion_result<IntegerType> try_as_integer() const
33753376
{
3377+
using result_type = conversion_result<IntegerType>;
3378+
33763379
switch (storage_kind())
33773380
{
33783381
case json_storage_kind::short_str:
@@ -3382,27 +3385,38 @@ namespace jsoncons {
33823385
auto result = jsoncons::utility::to_integer<IntegerType>(as_string_view().data(), as_string_view().length(), val);
33833386
if (!result)
33843387
{
3385-
JSONCONS_THROW(json_runtime_error<std::runtime_error>(result.error_code().message()));
3388+
return result_type(unexpect, conv_errc::not_integer);
33863389
}
33873390
return val;
33883391
}
33893392
case json_storage_kind::half_float:
3390-
return static_cast<IntegerType>(cast<half_storage>().value());
3393+
return result_type(static_cast<IntegerType>(cast<half_storage>().value()));
33913394
case json_storage_kind::float64:
3392-
return static_cast<IntegerType>(cast<double_storage>().value());
3395+
return result_type(static_cast<IntegerType>(cast<double_storage>().value()));
33933396
case json_storage_kind::int64:
3394-
return static_cast<IntegerType>(cast<int64_storage>().value());
3397+
return result_type(static_cast<IntegerType>(cast<int64_storage>().value()));
33953398
case json_storage_kind::uint64:
3396-
return static_cast<IntegerType>(cast<uint64_storage>().value());
3399+
return result_type(static_cast<IntegerType>(cast<uint64_storage>().value()));
33973400
case json_storage_kind::boolean:
3398-
return static_cast<IntegerType>(cast<bool_storage>().value() ? 1 : 0);
3401+
return result_type(static_cast<IntegerType>(cast<bool_storage>().value() ? 1 : 0));
33993402
case json_storage_kind::json_const_reference:
3400-
return cast<json_const_reference_storage>().value().template as_integer<IntegerType>();
3403+
return cast<json_const_reference_storage>().value().template try_as_integer<IntegerType>();
34013404
case json_storage_kind::json_reference:
3402-
return cast<json_reference_storage>().value().template as_integer<IntegerType>();
3405+
return cast<json_reference_storage>().value().template try_as_integer<IntegerType>();
34033406
default:
3404-
JSONCONS_THROW(json_runtime_error<std::domain_error>("Not an integer"));
3407+
return result_type(unexpect, conv_errc::not_integer);
3408+
}
3409+
}
3410+
3411+
template <typename IntegerType>
3412+
IntegerType as_integer() const
3413+
{
3414+
auto result = try_as_integer<IntegerType>();
3415+
if (!result)
3416+
{
3417+
JSONCONS_THROW(conv_error(result.error().code()));
34053418
}
3419+
return result.value();
34063420
}
34073421

34083422
template <typename IntegerType>
@@ -3495,8 +3509,10 @@ namespace jsoncons {
34953509
}
34963510
}
34973511

3498-
double as_double() const
3512+
conversion_result<double> try_as_double() const
34993513
{
3514+
using result_type = conversion_result<double>;
3515+
35003516
switch (storage_kind())
35013517
{
35023518
case json_storage_kind::short_str:
@@ -3510,43 +3526,53 @@ namespace jsoncons {
35103526
auto result = jsoncons::utility::hexstr_to_double(s, len, x);
35113527
if (result.ec == std::errc::invalid_argument)
35123528
{
3513-
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("Not a double"));
3529+
return result_type(unexpect, conv_errc::not_double);
35143530
}
35153531
}
35163532
else if (JSONCONS_UNLIKELY(len > 3 && s[0] == '-' && s[1] == '0' && (s[2] == 'x' || s[2] == 'X')))
35173533
{
35183534
auto result = jsoncons::utility::hexstr_to_double(s, len, x);
35193535
if (result.ec == std::errc::invalid_argument)
35203536
{
3521-
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("Not a double"));
3537+
return result_type(unexpect, conv_errc::not_double);
35223538
}
35233539
}
35243540
else
35253541
{
35263542
auto result = jsoncons::utility::decstr_to_double(as_cstring(), as_string_view().length(), x);
35273543
if (result.ec == std::errc::invalid_argument)
35283544
{
3529-
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("Not a double"));
3545+
return result_type(unexpect, conv_errc::not_double);
35303546
}
35313547
}
35323548

3533-
return x;
3549+
return result_type(x);
35343550
}
35353551
case json_storage_kind::half_float:
3536-
return binary::decode_half(cast<half_storage>().value());
3552+
return result_type(binary::decode_half(cast<half_storage>().value()));
35373553
case json_storage_kind::float64:
3538-
return cast<double_storage>().value();
3554+
return result_type(cast<double_storage>().value());
35393555
case json_storage_kind::int64:
3540-
return static_cast<double>(cast<int64_storage>().value());
3556+
return result_type(static_cast<double>(cast<int64_storage>().value()));
35413557
case json_storage_kind::uint64:
3542-
return static_cast<double>(cast<uint64_storage>().value());
3558+
return result_type(static_cast<double>(cast<uint64_storage>().value()));
35433559
case json_storage_kind::json_const_reference:
3544-
return cast<json_const_reference_storage>().value().as_double();
3560+
return cast<json_const_reference_storage>().value().try_as_double();
35453561
case json_storage_kind::json_reference:
3546-
return cast<json_reference_storage>().value().as_double();
3562+
return cast<json_reference_storage>().value().try_as_double();
35473563
default:
3548-
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("Not a double"));
3564+
return result_type(unexpect, conv_errc::not_double);
3565+
}
3566+
}
3567+
3568+
double as_double() const
3569+
{
3570+
auto result = try_as_double();
3571+
if (!result)
3572+
{
3573+
JSONCONS_THROW(conv_error(result.error().code()));
35493574
}
3575+
return result.value();
35503576
}
35513577

35523578
template <typename SAllocator=std::allocator<char_type>>

include/jsoncons/reflect/json_conv_traits.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ has_can_convert = ext_traits::is_detected<traits_can_convert_t, Json, T>;
202202
}
203203
static result_type try_as(const Json& j)
204204
{
205-
return result_type{j.template as_integer<T>()};
205+
return j.template try_as_integer<T>();
206206
}
207207

208208
static Json to_json(T val)
@@ -253,7 +253,12 @@ has_can_convert = ext_traits::is_detected<traits_can_convert_t, Json, T>;
253253
}
254254
static result_type try_as(const Json& j)
255255
{
256-
return result_type(static_cast<T>(j.as_double()));
256+
auto result = j.try_as_double();
257+
if (JSONCONS_UNLIKELY(!result))
258+
{
259+
return result_type(result.error().code());
260+
}
261+
return result_type(static_cast<T>(result.value()));
257262
}
258263
static Json to_json(T val)
259264
{

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ add_executable(unit_tests
179179
corelib/src/json_conv_traits_chrono_tests.cpp
180180
corelib/src/json_conv_traits_string_tests.cpp
181181
corelib/src/reflect_traits_container_tests.cpp
182+
corelib/src/reflect/json_conv_traits_tests.cpp
182183
corelib/src/json_type_traits_tests.cpp
183184
corelib/src/json_validation_tests.cpp
184185
corelib/src/jsoncons_tests.cpp

test/corelib/src/reflect/json_conv_traits_tests.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@
1414
#include <cstdint>
1515
#include <catch/catch.hpp>
1616

17+
namespace {
1718
namespace ns {
19+
1820
struct book
1921
{
2022
std::string author;
2123
std::string title;
2224
double price{0};
2325
};
26+
2427
} // namespace ns
28+
} // namespace
2529

2630
namespace jsoncons {
2731
namespace reflect {
@@ -30,7 +34,7 @@ template <typename Json>
3034
struct json_conv_traits<Json, ns::book>
3135
{
3236
using result_type = conversion_result<ns::book>;
33-
using allocator_type = Json::allocator_type;
37+
using allocator_type = typename Json::allocator_type;
3438

3539
static bool is(const Json& j) noexcept
3640
{
@@ -119,4 +123,28 @@ TEST_CASE("json_conv_traits tests")
119123
}
120124
}
121125

126+
TEST_CASE("json_conv_traits error tests")
127+
{
128+
SECTION("double")
129+
{
130+
auto j = jsoncons::json::parse(R"("foo")");
131+
REQUIRE(j.is_string());
132+
133+
auto result = jsoncons::reflect::json_conv_traits<jsoncons::json,double>::try_as(j);
134+
REQUIRE_FALSE(result);
135+
REQUIRE(jsoncons::conv_errc::not_double == result.error().code());
136+
//std::cout << result.error() << "\n\n";
137+
}
138+
SECTION("int64_t")
139+
{
140+
auto j = jsoncons::json::parse(R"("foo")");
141+
REQUIRE(j.is_string());
142+
143+
auto result = jsoncons::reflect::json_conv_traits<jsoncons::json,int64_t>::try_as(j);
144+
REQUIRE_FALSE(result);
145+
REQUIRE(jsoncons::conv_errc::not_integer == result.error().code());
146+
//std::cout << result.error() << "\n\n";
147+
}
148+
}
149+
122150

0 commit comments

Comments
 (0)