From 47b3078c93a763f67103ff67f0fe8b6ac5794370 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 17 Mar 2021 13:54:18 +0100 Subject: SL-14999 - C++ feature tests --- indra/newview/tests/cppfeatures_test.cpp | 372 ++++++++++++++++++++----------- 1 file changed, 245 insertions(+), 127 deletions(-) (limited to 'indra/newview/tests') diff --git a/indra/newview/tests/cppfeatures_test.cpp b/indra/newview/tests/cppfeatures_test.cpp index 15aa1cd6d6..8399bb12ff 100644 --- a/indra/newview/tests/cppfeatures_test.cpp +++ b/indra/newview/tests/cppfeatures_test.cpp @@ -1,127 +1,245 @@ -/** - * @file cppfeatures_test - * @author Vir - * @date 2021-03 - * @brief cpp features - * - * $LicenseInfo:firstyear=2021&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2021, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// Tests related to newer C++ features, for verifying support across compilers and platforms - -#include "linden_common.h" -#include "../test/lltut.h" - -namespace tut -{ - -struct cpp_features_test {}; -typedef test_group cpp_features_test_t; -typedef cpp_features_test_t::object cpp_features_test_object_t; -tut::cpp_features_test_t tut_cpp_features_test("LLCPPFeatures"); - -// bracket initializers -// Can initialize containers or values using curly brackets -template<> template<> -void cpp_features_test_object_t::test<1>() -{ - S32 explicit_val{3}; - ensure(explicit_val==3); - - S32 default_val{}; - ensure(default_val==0); - - std::vector fibs{1,1,2,3,5}; - ensure(fibs[4]==5); -} - -// auto -// -// https://en.cppreference.com/w/cpp/language/auto -// -// Can use auto in place of a more complex type specification, if the compiler can infer the type -template<> template<> -void cpp_features_test_object_t::test<2>() -{ - std::vector numbers{3,6,9}; - - // auto element - auto& aval = numbers[1]; - ensure("auto element", aval==6); - - // auto iterator (non-const) - auto it = numbers.rbegin(); - *it += 1; - S32 val = *it; - ensure("auto iterator", val==10); -} - -// range for -// -// https://en.cppreference.com/w/cpp/language/range-for -// -// Can iterate over containers without explicit iterator -template<> template<> -void cpp_features_test_object_t::test<3>() -{ - - // Traditional iterator for with container - // - // Problems: - // * Have to create a new variable for the iterator, which is unrelated to the problem you're trying to solve. - // * Redundant and somewhat fragile. Have to make sure begin() and end() are both from the right container. - std::vector numbers{3,6,9}; - for (auto it = numbers.begin(); it != numbers.end(); ++it) - { - auto& n = *it; - n *= 2; - } - ensure("iterator for vector", numbers[2]==18); - - // Range for with container - // - // Under the hood, this is doing the same thing as the traditional - // for loop above. Still uses begin() and end() but you don't have - // to access them directly. - std::vector numbersb{3,6,9}; - for (auto& n: numbersb) - { - n *= 2; - } - ensure("range for vector", numbersb[2]==18); - - // Range for over a C-style array. - // - // This is handy because the language determines the range automatically. - // Getting this right manually is a little trickier. - S32 pows[] = {1,2,4,8,16}; - S32 sum{}; - for (const auto& v: pows) - { - sum += v; - } - ensure("for C-array", sum==31); -} - - - -} +/** + * @file cppfeatures_test + * @author Vir + * @date 2021-03 + * @brief cpp features + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Tests related to newer C++ features, for verifying support across compilers and platforms + +#include "linden_common.h" +#include "../test/lltut.h" + +namespace tut +{ + +struct cpp_features_test {}; +typedef test_group cpp_features_test_t; +typedef cpp_features_test_t::object cpp_features_test_object_t; +tut::cpp_features_test_t tut_cpp_features_test("LLCPPFeatures"); + +// bracket initializers +// Can initialize containers or values using curly brackets +template<> template<> +void cpp_features_test_object_t::test<1>() +{ + S32 explicit_val{3}; + ensure(explicit_val==3); + + S32 default_val{}; + ensure(default_val==0); + + std::vector fibs{1,1,2,3,5}; + ensure(fibs[4]==5); +} + +// auto +// +// https://en.cppreference.com/w/cpp/language/auto +// +// Can use auto in place of a more complex type specification, if the compiler can infer the type +template<> template<> +void cpp_features_test_object_t::test<2>() +{ + std::vector numbers{3,6,9}; + + // auto element + auto& aval = numbers[1]; + ensure("auto element", aval==6); + + // auto iterator (non-const) + auto it = numbers.rbegin(); + *it += 1; + S32 val = *it; + ensure("auto iterator", val==10); +} + +// range for +// +// https://en.cppreference.com/w/cpp/language/range-for +// +// Can iterate over containers without explicit iterator +template<> template<> +void cpp_features_test_object_t::test<3>() +{ + + // Traditional iterator for with container + // + // Problems: + // * Have to create a new variable for the iterator, which is unrelated to the problem you're trying to solve. + // * Redundant and somewhat fragile. Have to make sure begin() and end() are both from the right container. + std::vector numbers{3,6,9}; + for (auto it = numbers.begin(); it != numbers.end(); ++it) + { + auto& n = *it; + n *= 2; + } + ensure("iterator for vector", numbers[2]==18); + + // Range for with container + // + // Under the hood, this is doing the same thing as the traditional + // for loop above. Still uses begin() and end() but you don't have + // to access them directly. + std::vector numbersb{3,6,9}; + for (auto& n: numbersb) + { + n *= 2; + } + ensure("range for vector", numbersb[2]==18); + + // Range for over a C-style array. + // + // This is handy because the language determines the range automatically. + // Getting this right manually is a little trickier. + S32 pows[] = {1,2,4,8,16}; + S32 sum{}; + for (const auto& v: pows) + { + sum += v; + } + ensure("for C-array", sum==31); +} + +// override specifier +// +// https://en.cppreference.com/w/cpp/language/override +// +// Specify that a particular class function is an override of a virtual function. +// Benefits: +// * Makes code somewhat easier to read by showing intent. +// * Prevents mistakes where you think something is an override but it doesn't actually match the declaration in the parent class. +// Drawbacks: +// * Some compilers require that any class using override must use it consistently for all functions. +// This makes switching a class to use override a lot more work. + +class Foo +{ +public: + virtual bool is_happy() const = 0; +}; + +class Bar: public Foo +{ +public: + bool is_happy() const override { return true; } + // Override would fail: non-const declaration doesn't match parent + // bool is_happy() override { return true; } + // Override would fail: wrong name + // bool is_happx() override { return true; } +}; + +template<> template<> +void cpp_features_test_object_t::test<4>() +{ + Bar b; + ensure("override", b.is_happy()); +} + +// final +// +// https://en.cppreference.com/w/cpp/language/final: "Specifies that a +// virtual function cannot be overridden in a derived class or that a +// class cannot be inherited from." + +class Vehicle +{ +public: + virtual bool has_wheels() const = 0; +}; + +class WheeledVehicle: public Vehicle +{ +public: + virtual bool has_wheels() const final override { return true; } +}; + +class Bicycle: public WheeledVehicle +{ +public: + // Error: can't override final version in WheeledVehicle + // virtual bool has_wheels() override const { return true; } +}; + +template<> template<> +void cpp_features_test_object_t::test<5>() +{ + Bicycle bi; + ensure("final", bi.has_wheels()); +} + +// deleted function declaration +// +// https://en.cppreference.com/w/cpp/language/function#Deleted_functions +// +// Typical case: copy constructor doesn't make sense for a particular class, so you want to make +// sure the no one tries to copy-construct an instance of the class, and that the +// compiler won't generate a copy constructor for you automatically. +// Traditional fix is to declare a +// copy constructor but never implement it, giving you a link-time error if anyone tries to use it. +// Now you can explicitly declare a function to be deleted, which has at least two advantages over +// the old way: +// * Makes the intention clear +// * Creates an error sooner, at compile time + +class DoNotCopy +{ +public: + DoNotCopy() {} + DoNotCopy(const DoNotCopy& ref) = delete; +}; + +template<> template<> +void cpp_features_test_object_t::test<6>() +{ + DoNotCopy nc; // OK, default constructor + //DoNotCopy nc2(nc); // No, can't copy + //DoNotCopy nc3 = nc; // No, this also calls copy constructor (even though it looks like an assignment) +} + +// defaulted function declaration +// +// https://en.cppreference.com/w/cpp/language/function#Function_definition +// +// What about the complementary case to the deleted function declaration, where you want a copy constructor +// and are happy with the default implementation the compiler will make (memberwise copy). +// Now you can explicitly declare that too. +// Usage: I guess it makes the intent clearer, but otherwise not obviously useful. +class DefaultCopyOK +{ +public: + DefaultCopyOK() {} + DefaultCopyOK(const DefaultCopyOK&) = default; +}; + +template<> template<> +void cpp_features_test_object_t::test<7>() +{ + DefaultCopyOK d; // OK + DefaultCopyOK d2(d); // OK + DefaultCopyOK d3 = d; // OK +} + + +} // namespace tut -- cgit v1.2.3