Skip to content

Commit 98391b4

Browse files
authored
Ensure all C++ code is C++11 compatible
2 parents 6b3dd75 + 3a570ee commit 98391b4

File tree

6 files changed

+53
-30
lines changed

6 files changed

+53
-30
lines changed

.github/workflows/unit-tests.yml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,22 @@ jobs:
1818
fail-fast: false
1919
matrix:
2020
config:
21-
- { os: "ubuntu-latest", R: "latest" }
22-
- { os: "macOS-latest", R: "latest" }
21+
22+
# Check latest R versions
23+
- { os: "ubuntu-latest", R: "latest" }
24+
- { os: "macOS-latest", R: "latest" }
2325
- { os: "windows-latest", R: "latest" }
24-
- { os: "ubuntu-latest", R: "devel" }
26+
- { os: "ubuntu-latest", R: "devel" }
2527
- { os: "windows-latest", R: "devel" }
2628

29+
# Check older versions of R
30+
- { os: "ubuntu-latest", R: 'oldrel-1'}
31+
- { os: "ubuntu-latest", R: 'oldrel-2'}
32+
- { os: "ubuntu-latest", R: 'oldrel-3'}
33+
- { os: "ubuntu-latest", R: 'oldrel-4'}
34+
35+
- { os: "windows-latest", R: "oldrel-4" }
36+
2737
env:
2838
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
2939
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

paws.common/DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: paws.common
22
Type: Package
33
Title: Paws Low-Level Amazon Web Services API
4-
Version: 0.8.7
4+
Version: 0.8.8
55
Authors@R: c(
66
person("David", "Kretch", email = "david.kretch@gmail.com", role = "aut"),
77
person("Adam", "Banker", email = "adam.banker39@gmail.com", role = "aut"),
@@ -14,6 +14,7 @@ Description: Functions for making low-level API requests to Amazon Web Services
1414
higher-level interfaces to individual services, such as Simple Storage
1515
Service (S3).
1616
License: Apache License (>= 2.0)
17+
Depends: R (>= 4.1.0)
1718
URL: https://github.com/paws-r/paws, https://paws-r.r-universe.dev/paws.common, https://www.paws-r-sdk.com
1819
BugReports: https://github.com/paws-r/paws/issues
1920
Encoding: UTF-8

paws.common/NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# paws.common 0.8.8
2+
* fix C++ compilation issues on older R versions by refactoring code to use C++11 standard and requiring R >= 4.1.0 (#957). Thanks to @detule for raising the issue.
3+
14
# paws.common 0.8.7
25
* fix timezone handling in bearer token tests (#955). Thanks to @kyleam for raising issue.
36

paws.common/src/RcppExports.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ BEGIN_RCPP
6868
END_RCPP
6969
}
7070
// json_build_any
71-
std::string json_build_any(SEXP values);
71+
CharacterVector json_build_any(SEXP values);
7272
RcppExport SEXP _paws_common_json_build_any(SEXP valuesSEXP) {
7373
BEGIN_RCPP
7474
Rcpp::RObject rcpp_result_gen;

paws.common/src/json_builder.cpp

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ inline std::string tag_get(SEXP object, const char *tag)
6767
case STRSXP:
6868
if (Rf_length(val) > 0)
6969
{
70-
return std::string(CHAR(STRING_ELT(val, 0)));
70+
return std::string(Rf_translateCharUTF8(STRING_ELT(val, 0)));
7171
}
7272
break;
7373
case LGLSXP:
@@ -135,8 +135,8 @@ std::string type(SEXP object)
135135
}
136136

137137
// -------------------- Forward declaration --------------------
138-
// This function will be defined later and called recursively
139-
std::string json_build_any(SEXP values);
138+
// Internal function that builds JSON and returns std::string (used internally)
139+
std::string json_build_internal(SEXP values);
140140

141141
// -------------------- Helper function to safely convert to string --------------------
142142
// This function converts an SEXP to a string representation, handling various R types.
@@ -151,17 +151,17 @@ std::string safe_as_string(SEXP x)
151151
switch (type)
152152
{
153153
case STRSXP:
154-
// Directly return string for character SEXPs
155-
return std::string(CHAR(STRING_ELT(x, 0)));
154+
// Directly return string for character SEXPs, ensuring UTF-8 encoding
155+
return std::string(Rf_translateCharUTF8(STRING_ELT(x, 0)));
156156
case INTSXP:
157157
case REALSXP:
158158
case LGLSXP:
159159
case RAWSXP:
160160
// Coerce to character and then return string for numeric, logical, raw
161-
return std::string(CHAR(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
161+
return std::string(Rf_translateCharUTF8(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
162162
default:
163163
// Coerce any other type to character as a fallback
164-
return std::string(CHAR(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
164+
return std::string(Rf_translateCharUTF8(STRING_ELT(Rf_coerceVector(x, STRSXP), 0)));
165165
}
166166
}
167167

@@ -255,7 +255,7 @@ std::string json_build_list(SEXP values)
255255
for (R_xlen_t i = 0; i < n; i++)
256256
{
257257
// Recursively build JSON for each element
258-
std::string elem_json = json_build_any(VECTOR_ELT(values, i));
258+
std::string elem_json = json_build_internal(VECTOR_ELT(values, i));
259259
// Only add non-empty elements, excluding "empty" JSON array/object strings
260260
if (!elem_json.empty() && elem_json != "[]" && elem_json != "{}")
261261
{
@@ -325,7 +325,7 @@ std::string json_build_structure(SEXP values)
325325
}
326326

327327
// Recursively build JSON for the payload's value
328-
return json_build_any(payload_val);
328+
return json_build_internal(payload_val);
329329
}
330330

331331
SEXP names = Rf_getAttrib(values, symbol_cache.names_sym);
@@ -360,11 +360,11 @@ std::string json_build_structure(SEXP values)
360360
val = uuid_val; // Use the newly created UUID SEXP
361361
}
362362

363-
std::string key = CHAR(STRING_ELT(names, i)); // Get the field name
363+
std::string key = Rf_translateCharUTF8(STRING_ELT(names, i)); // Get the field name
364364
std::string loc_name = tag_get(val, "locationName"); // Check for locationName tag
365365
std::string name = loc_name.empty() ? key : loc_name; // Use locationName if present
366366

367-
std::string json_val = json_build_any(val); // Recursively build JSON for field value
367+
std::string json_val = json_build_internal(val); // Recursively build JSON for field value
368368
// Only add non-empty fields, excluding "empty" JSON array/object strings
369369
if (!json_val.empty() && json_val != "[]" && json_val != "{}")
370370
{
@@ -420,14 +420,14 @@ inline std::string json_build_map(SEXP values)
420420
// Populate the vector with key-value pairs from the R object
421421
for (R_xlen_t i = 0; i < n; ++i)
422422
{
423-
std::string key = CHAR(STRING_ELT(names_sexp, i));
423+
std::string key = Rf_translateCharUTF8(STRING_ELT(names_sexp, i));
424424
SEXP val = VECTOR_ELT(values, i);
425425
named_elements.push_back({key, val});
426426
}
427427

428428
// Sort the vector based on the string key in each pair
429429
std::sort(named_elements.begin(), named_elements.end(),
430-
[](const auto &a, const auto &b)
430+
[](const std::pair<std::string, SEXP> &a, const std::pair<std::string, SEXP> &b)
431431
{
432432
return a.first < b.first;
433433
});
@@ -442,7 +442,7 @@ inline std::string json_build_map(SEXP values)
442442
SEXP val = element.second;
443443

444444
// Recursively build JSON for the value
445-
std::string json_val = json_build_any(val);
445+
std::string json_val = json_build_internal(val);
446446

447447
// Only add non-empty pairs to the final JSON string
448448
if (!json_val.empty() && json_val != "[]" && json_val != "{}")
@@ -469,17 +469,8 @@ inline std::string json_build_map(SEXP values)
469469
return result;
470470
}
471471

472-
/**
473-
* @brief Build Json Strings Using AWS Attributes for JSON Template
474-
*
475-
* @param object A list to be parsed into JSON string
476-
*
477-
* @return a JSON String
478-
*/
479-
//' @useDynLib paws.common _paws_common_json_build_any
480-
//' @importFrom Rcpp evalCpp
481-
// [[Rcpp::export]]
482-
std::string json_build_any(SEXP values)
472+
// Internal implementation that returns std::string (used by recursive calls)
473+
std::string json_build_internal(SEXP values)
483474
{
484475
// Determine the effective type of the R object for JSON building
485476
std::string t = type(values);
@@ -494,3 +485,20 @@ std::string json_build_any(SEXP values)
494485
// Default to scalar if none of the above, or if `type` returns "scalar"
495486
return json_build_scalar(values);
496487
}
488+
489+
/**
490+
* @brief Build Json Strings Using AWS Attributes for JSON Template
491+
*
492+
* @param object A list to be parsed into JSON string
493+
*
494+
* @return a JSON String
495+
*/
496+
//' @useDynLib paws.common _paws_common_json_build_any
497+
//' @importFrom Rcpp evalCpp
498+
// [[Rcpp::export]]
499+
CharacterVector json_build_any(SEXP values)
500+
{
501+
// Call internal implementation and UTF-8 encode result
502+
std::string result = json_build_internal(values);
503+
return CharacterVector::create(String(result, CE_UTF8));
504+
}

paws.common/src/json_escape.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ CharacterVector json_convert_string(CharacterVector x)
143143
for (int i = 0; i < n; ++i)
144144
{
145145
String cur = x[i];
146+
cur.set_encoding(CE_UTF8); // Ensure UTF-8 encoding
146147
out[i] = json_escape(cur);
147148
}
148149
return out;

0 commit comments

Comments
 (0)