diff --git a/.ci/test.sh b/.ci/test.sh index 8b1bfd13ebe6..539c5c61d3f3 100755 --- a/.ci/test.sh +++ b/.ci/test.sh @@ -64,7 +64,7 @@ if [[ $TASK == "lint" ]]; then echo "Linting R code" Rscript ${BUILD_DIRECTORY}/.ci/lint_r_code.R ${BUILD_DIRECTORY} || exit -1 echo "Linting C++ code" - cpplint --filter=-build/c++11,-build/include_subdir,-build/header_guard,-whitespace/line_length --recursive ./src ./include ./R-package || exit -1 + cpplint --filter=-build/c++11,-build/include_subdir,-build/header_guard,-whitespace/line_length --recursive ./src ./include ./R-package ./swig || exit -1 exit 0 fi diff --git a/swig/ChunkedArray.hpp b/swig/ChunkedArray.hpp index 122dd489da0f..711a63b502aa 100644 --- a/swig/ChunkedArray.hpp +++ b/swig/ChunkedArray.hpp @@ -1,3 +1,9 @@ +/*! + * Copyright (c) 2021 Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + * + * Author: Alberto Ferreira + */ #ifndef __CHUNKED_ARRAY_H__ #define __CHUNKED_ARRAY_H__ @@ -50,8 +56,8 @@ */ template class ChunkedArray { - public: - ChunkedArray(size_t chunk_size) + public: + explicit ChunkedArray(size_t chunk_size) : _chunk_size(chunk_size), _last_chunk_idx(0), _last_idx_in_last_chunk(0) { new_chunk(); } @@ -73,7 +79,7 @@ class ChunkedArray { _last_idx_in_last_chunk = 0; } - assert (setitem(_last_chunk_idx, _last_idx_in_last_chunk, value) == 0); + assert(setitem(_last_chunk_idx, _last_idx_in_last_chunk, value) == 0); ++_last_idx_in_last_chunk; } @@ -141,16 +147,16 @@ class ChunkedArray { // Copy full chunks: size_t i = 0; - for(size_t chunk = 0; chunk < full_chunks; ++chunk) { + for (size_t chunk = 0; chunk < full_chunks; ++chunk) { T* chunk_ptr = _chunks[chunk]; - for(size_t chunk_pos = 0; chunk_pos < _chunk_size; ++chunk_pos) { + for (size_t chunk_pos = 0; chunk_pos < _chunk_size; ++chunk_pos) { other[i++] = chunk_ptr[chunk_pos]; } } // Copy filled values from last chunk only: const size_t last_chunk_elems = this->get_last_chunk_add_count(); T* chunk_ptr = _chunks[full_chunks]; - for(size_t chunk_pos = 0; chunk_pos < last_chunk_elems; ++chunk_pos) { + for (size_t chunk_pos = 0; chunk_pos < last_chunk_elems; ++chunk_pos) { other[i++] = chunk_ptr[chunk_pos]; } } @@ -164,7 +170,7 @@ class ChunkedArray { * * @return pointer or nullptr if index is out of bounds. */ - T getitem(size_t chunk_index, size_t index_within_chunk, T on_fail_value) noexcept { + T getitem(size_t chunk_index, size_t index_within_chunk, T on_fail_value) const noexcept { if (within_bounds(chunk_index, index_within_chunk)) return _chunks[chunk_index][index_within_chunk]; else @@ -181,8 +187,7 @@ class ChunkedArray { * @return 0 = success, -1 = out of bounds access. */ int setitem(size_t chunk_index, size_t index_within_chunk, T value) noexcept { - if (within_bounds(chunk_index, index_within_chunk)) - { + if (within_bounds(chunk_index, index_within_chunk)) { _chunks[chunk_index][index_within_chunk] = value; return 0; } else { @@ -225,7 +230,7 @@ class ChunkedArray { * @param index_within_chunk index within that chunk * @return true if that chunk is already allocated and index_within_chunk < chunk size. */ - inline bool within_bounds(size_t chunk_index, size_t index_within_chunk) { + inline bool within_bounds(size_t chunk_index, size_t index_within_chunk) const { return (chunk_index < _chunks.size()) && (index_within_chunk < _chunk_size); } @@ -238,11 +243,11 @@ class ChunkedArray { // Check memory allocation success: if (!_chunks[_chunks.size()-1]) { release(); - throw std::bad_alloc("Couldn't add more chunks to ChunkedArray. Released memory!"); + throw std::bad_alloc(); } } - private: + private: const size_t _chunk_size; std::vector _chunks; diff --git a/swig/StringArray.hpp b/swig/StringArray.hpp index 397f2c46c8be..76b715b64ddc 100644 --- a/swig/StringArray.hpp +++ b/swig/StringArray.hpp @@ -1,13 +1,16 @@ /*! * Copyright (c) 2020 Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See LICENSE file in the project root for license information. + * + * Author: Alberto Ferreira */ #ifndef __STRING_ARRAY_H__ #define __STRING_ARRAY_H__ +#include #include +#include #include -#include /** * Container that manages an array of fixed-length strings. @@ -22,18 +25,15 @@ * The class also takes care of allocation of the underlying * char* memory. */ -class StringArray -{ - public: +class StringArray { + public: StringArray(size_t num_elements, size_t string_size) : _string_size(string_size), - _array(num_elements + 1, nullptr) - { + _array(num_elements + 1, nullptr) { _allocate_strings(num_elements, string_size); } - ~StringArray() - { + ~StringArray() { _release_strings(); } @@ -43,8 +43,7 @@ class StringArray * * @return char** pointer to raw data (null-terminated). */ - char **data() noexcept - { + char **data() noexcept { return _array.data(); } @@ -56,8 +55,7 @@ class StringArray * @param index Index of the element to retrieve. * @return pointer or nullptr if index is out of bounds. */ - char *getitem(size_t index) noexcept - { + char *getitem(size_t index) noexcept { if (_in_bounds(index)) return _array[index]; else @@ -77,11 +75,9 @@ class StringArray * into the target string (_string_size), it errors out * and returns -1. */ - int setitem(size_t index, std::string content) noexcept - { - if (_in_bounds(index) && content.size() < _string_size) - { - std::strcpy(_array[index], content.c_str()); + int setitem(size_t index, const std::string &content) noexcept { + if (_in_bounds(index) && content.size() < _string_size) { + std::strcpy(_array[index], content.c_str()); // NOLINT return 0; } else { return -1; @@ -91,13 +87,11 @@ class StringArray /** * @return number of stored strings. */ - size_t get_num_elements() noexcept - { + size_t get_num_elements() noexcept { return _array.size() - 1; } - private: - + private: /** * Returns true if and only if within bounds. * Notice that it excludes the last element of _array (NULL). @@ -105,8 +99,7 @@ class StringArray * @param index index of the element * @return bool true if within bounds */ - bool _in_bounds(size_t index) noexcept - { + bool _in_bounds(size_t index) noexcept { return index < get_num_elements(); } @@ -120,15 +113,13 @@ class StringArray * @param num_elements Number of strings to store in the array. * @param string_size The size of each string in the array. */ - void _allocate_strings(size_t num_elements, size_t string_size) - { - for (size_t i = 0; i < num_elements; ++i) - { + void _allocate_strings(size_t num_elements, size_t string_size) { + for (size_t i = 0; i < num_elements; ++i) { // Leave space for \0 terminator: _array[i] = new (std::nothrow) char[string_size + 1]; // Check memory allocation: - if (! _array[i]) { + if (!_array[i]) { _release_strings(); throw std::bad_alloc(); } @@ -138,8 +129,7 @@ class StringArray /** * Deletes the allocated strings. */ - void _release_strings() noexcept - { + void _release_strings() noexcept { std::for_each(_array.begin(), _array.end(), [](char* c) { delete[] c; }); } @@ -147,4 +137,4 @@ class StringArray std::vector _array; }; -#endif // __STRING_ARRAY_H__ +#endif // __STRING_ARRAY_H__ diff --git a/swig/test_ChunkedArray_manually.cpp b/swig/test_ChunkedArray_manually.cpp index 383a75aa0308..75601d0fe555 100644 --- a/swig/test_ChunkedArray_manually.cpp +++ b/swig/test_ChunkedArray_manually.cpp @@ -1,3 +1,9 @@ +/*! + * Copyright (c) 2021 Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE file in the project root for license information. + * + * Author: Alberto Ferreira + */ /** * Tests for ChunkedArray. * @@ -12,18 +18,19 @@ #include #include "ChunkedArray.hpp" -using namespace std; +using std::cout; +using std::endl; -using intChunkedArray=ChunkedArray; +using intChunkedArray = ChunkedArray; using doubleChunkedArray = ChunkedArray; // Test data -const int out_of_bounds = 4; // test get outside bounds. +const int out_of_bounds = 4; // test get outside bounds. const size_t chunk_size = 3; const std::vector ref = {1, 2, 3, 4, 5, 6, 7}; template -size_t _get_merged_array_size(ChunkedArray &ca) { +size_t _get_merged_array_size(const ChunkedArray &ca) { if (ca.empty()) { return 0; } else { @@ -33,7 +40,7 @@ size_t _get_merged_array_size(ChunkedArray &ca) { } template -void print_container_stats(ChunkedArray &ca) { +void print_container_stats(const ChunkedArray &ca) { printf("\n\nContainer stats: %ld chunks of size %ld with %ld item(s) on last chunk (#elements=%ld).\n" " > Should result in single array of size %ld.\n\n", ca.get_chunks_count(), @@ -44,7 +51,7 @@ void print_container_stats(ChunkedArray &ca) { } template -void _print_chunked_data(ChunkedArray &x, T** data, std::ostream &o = std::cout) { +void _print_chunked_data(const ChunkedArray &x, T** data, std::ostream &o = std::cout) { int chunk = 0; int pos = 0; @@ -61,27 +68,26 @@ void _print_chunked_data(ChunkedArray &x, T** data, std::ostream &o = std::co } template -void print_data(ChunkedArray &x) { - T **data = x.data(); +void print_data(ChunkedArray *x) { + T **data = x->data(); cout << "Printing from T** data(): \n"; - _print_chunked_data(x, data); + _print_chunked_data(*x, data); cout << "\n^ Print complete ^\n"; } template -void print_void_data(ChunkedArray &x) { - T **data = reinterpret_cast(x.data_as_void()); +void print_void_data(ChunkedArray *x) { + T **data = reinterpret_cast(x->data_as_void()); cout << "Printing from reinterpret_cast(data_as_void()):\n"; - _print_chunked_data(x, data); + _print_chunked_data(*x, data); cout << "\n^ Print complete ^\n"; } template -void print_ChunkedArray_contents(ChunkedArray &ca) { +void print_ChunkedArray_contents(const ChunkedArray &ca) { int chunk = 0; int pos = 0; for (int i = 0; i < ca.get_add_count() + out_of_bounds; ++i) { - bool within_added = i < ca.get_add_count(); bool within_bounds = ca.within_bounds(chunk, pos); cout << "@(" << chunk << "," << pos << ") = " << ca.getitem(chunk, pos, 10) @@ -113,7 +119,7 @@ void test_coalesce_to(const intChunkedArray &ca, const std::vector &ref) { * that the data was stored correctly and with the correct memory layout. */ template -void test_data_layout(ChunkedArray &ca, const std::vector &ref, bool data_as_void) { +void test_data_layout(ChunkedArray *ca, const std::vector &ref, bool data_as_void) { std::stringstream ss, ss_ref; T **data = data_as_void? reinterpret_cast(ca.data_as_void()) : ca.data(); // Dump each chunk represented by a line with elements split by space: @@ -162,16 +168,16 @@ int main() { test_coalesce_to(ca, ref); // Test chunked data layout for retrieval: - test_data_layout(ca, ref, false); - test_data_layout(ca, ref, true); + test_data_layout(&ca, ref, false); + test_data_layout(&ca, ref, true); test_clear(); // For manual verification - useful outputs ////////////////////////////////////// print_container_stats(ca); print_ChunkedArray_contents(ca); - print_data(ca); - print_void_data(ca); + print_data(&ca); + print_void_data(&ca); ca.release(); ca.release(); print_container_stats(ca); // Check double free behaviour. cout << "Done!" << endl; return 0;