Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/mfbt/tests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  TestUniquePtr.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include <stddef.h>

#include <memory>  // For unique_ptr
#include <type_traits>
#include <utility>

#include "mozilla/Assertions.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/Vector.h"

using mozilla::DefaultDelete;
using mozilla::MakeUnique;
using mozilla::UniqueFreePtr;
using mozilla::UniquePtr;
using mozilla::Vector;

#define CHECK(c)                                  \
  do {                                            \
    bool cond = !!(c);                            \
    MOZ_RELEASE_ASSERT(cond, "Test failed: " #c); \
  } while (false)

typedef UniquePtr<int> NewInt;
static_assert(sizeof(NewInt) == sizeof(int*), "stored most efficiently");

static size_t gADestructorCalls = 0;

struct A {
 public:
  A() : mX(0) {}
  virtual ~A() { gADestructorCalls++; }

  int mX;
};

static size_t gBDestructorCalls = 0;

struct B : public A {
 public:
  B() : mY(1) {}
  ~B() { gBDestructorCalls++; }

  int mY;
};

typedef UniquePtr<A> UniqueA;
typedef UniquePtr<B, UniqueA::DeleterType> UniqueB;  // permit interconversion

static_assert(sizeof(UniqueA) == sizeof(A*), "stored most efficiently");
static_assert(sizeof(UniqueB) == sizeof(B*), "stored most efficiently");

struct DeleterSubclass : UniqueA::DeleterType {};

typedef UniquePtr<B, DeleterSubclass> UniqueC;
static_assert(sizeof(UniqueC) == sizeof(B*), "stored most efficiently");

static UniqueA ReturnUniqueA() { return UniqueA(new B); }

static UniqueA ReturnLocalA() {
  UniqueA a(new A);
  return a;
}

static void TestDeleterType() {
  // Make sure UniquePtr will use its deleter's pointer type if it defines one.
  typedef int* Ptr;
  struct Deleter {
    typedef Ptr pointer;
    Deleter() = default;
    void operator()(int* p) { delete p; }
  };
  UniquePtr<Ptr, Deleter> u(new int, Deleter());
}

static bool TestDefaultFreeGuts() {
  static_assert(std::is_same_v<NewInt::DeleterType, DefaultDelete<int> >,
                "weird deleter?");

  NewInt n1(new int);
  CHECK(n1);
  CHECK(n1.get() != nullptr);

  n1 = nullptr;
  CHECK(!n1);
  CHECK(n1.get() == nullptr);

  int* p1 = new int;
  n1.reset(p1);
  CHECK(n1);
  NewInt n2(std::move(n1));
  CHECK(!n1);
  CHECK(n1.get() == nullptr);
  CHECK(n2.get() == p1);

  std::swap(n1, n2);
  CHECK(n1.get() == p1);
  CHECK(n2.get() == nullptr);

  n1.swap(n2);
  CHECK(n1.get() == nullptr);
  CHECK(n2.get() == p1);
  delete n2.release();

  CHECK(n1.get() == nullptr);
  CHECK(n2 == nullptr);
  CHECK(nullptr == n2);

  int* p2 = new int;
  int* p3 = new int;
  n1.reset(p2);
  n2.reset(p3);
  CHECK(n1.get() == p2);
  CHECK(n2.get() == p3);

  n1.swap(n2);
  CHECK(n2 != nullptr);
  CHECK(nullptr != n2);
  CHECK(n2.get() == p2);
  CHECK(n1.get() == p3);

  UniqueA a1;
  CHECK(a1 == nullptr);
  a1.reset(new A);
  CHECK(gADestructorCalls == 0);
  CHECK(a1->mX == 0);

  B* bp1 = new B;
  bp1->mX = 5;
  CHECK(gBDestructorCalls == 0);
  a1.reset(bp1);
  CHECK(gADestructorCalls == 1);
  CHECK(a1->mX == 5);
  a1.reset(nullptr);
  CHECK(gADestructorCalls == 2);
  CHECK(gBDestructorCalls == 1);

  B* bp2 = new B;
  UniqueB b1(bp2);
  UniqueA a2(nullptr);
  a2 = std::move(b1);
  CHECK(gADestructorCalls == 2);
  CHECK(gBDestructorCalls == 1);

  UniqueA a3(std::move(a2));
  a3 = nullptr;
  CHECK(gADestructorCalls == 3);
  CHECK(gBDestructorCalls == 2);

  B* bp3 = new B;
  bp3->mX = 42;
  UniqueB b2(bp3);
  UniqueA a4(std::move(b2));
  CHECK(b2.get() == nullptr);
  CHECK((*a4).mX == 42);
  CHECK(gADestructorCalls == 3);
  CHECK(gBDestructorCalls == 2);

  UniqueA a5(new A);
  UniqueB b3(new B);
  a5 = std::move(b3);
  CHECK(gADestructorCalls == 4);
  CHECK(gBDestructorCalls == 2);

  ReturnUniqueA();
  CHECK(gADestructorCalls == 5);
  CHECK(gBDestructorCalls == 3);

  ReturnLocalA();
  CHECK(gADestructorCalls == 6);
  CHECK(gBDestructorCalls == 3);

  UniqueA a6(ReturnLocalA());
  a6 = nullptr;
  CHECK(gADestructorCalls == 7);
  CHECK(gBDestructorCalls == 3);

  UniqueC c1(new B);
  UniqueA a7(new B);
  a7 = std::move(c1);
  CHECK(gADestructorCalls == 8);
  CHECK(gBDestructorCalls == 4);

  c1.reset(new B);

  UniqueA a8(std::move(c1));
  CHECK(gADestructorCalls == 8);
  CHECK(gBDestructorCalls == 4);

  // These smart pointers still own B resources.
  CHECK(a4);
  CHECK(a5);
  CHECK(a7);
  CHECK(a8);
  return true;
}

static bool TestDefaultFree() {
  CHECK(TestDefaultFreeGuts());
  CHECK(gADestructorCalls == 12);
  CHECK(gBDestructorCalls == 8);
  return true;
}

static size_t FreeClassCounter = 0;

struct FreeClass {
 public:
  FreeClass() = default;

  void operator()(int* aPtr) {
    FreeClassCounter++;
    delete aPtr;
  }
};

typedef UniquePtr<int, FreeClass> NewIntCustom;
static_assert(sizeof(NewIntCustom) == sizeof(int*), "stored most efficiently");

static bool TestFreeClass() {
  CHECK(FreeClassCounter == 0);
  {
    NewIntCustom n1(new int);
    CHECK(FreeClassCounter == 0);
  }
  CHECK(FreeClassCounter == 1);

  NewIntCustom n2;
  {
    NewIntCustom n3(new int);
    CHECK(FreeClassCounter == 1);
    n2 = std::move(n3);
  }
  CHECK(FreeClassCounter == 1);
  n2 = nullptr;
  CHECK(FreeClassCounter == 2);

  n2.reset(nullptr);
  CHECK(FreeClassCounter == 2);
  n2.reset(new int);
  n2.reset();
  CHECK(FreeClassCounter == 3);

  NewIntCustom n4(new int, FreeClass());
  CHECK(FreeClassCounter == 3);
  n4.reset(new int);
  CHECK(FreeClassCounter == 4);
  n4.reset();
  CHECK(FreeClassCounter == 5);

  FreeClass f;
  NewIntCustom n5(new int, f);
  CHECK(FreeClassCounter == 5);
  int* p = n5.release();
  CHECK(FreeClassCounter == 5);
  delete p;

  return true;
}

typedef UniquePtr<int, DefaultDelete<int>&> IntDeleterRef;
typedef UniquePtr<A, DefaultDelete<A>&> ADeleterRef;
typedef UniquePtr<B, DefaultDelete<A>&> BDeleterRef;

static_assert(sizeof(IntDeleterRef) > sizeof(int*),
              "has to be heavier than an int* to store the reference");
static_assert(sizeof(ADeleterRef) > sizeof(A*),
              "has to be heavier than an A* to store the reference");
static_assert(sizeof(BDeleterRef) > sizeof(int*),
              "has to be heavier than a B* to store the reference");

static bool TestReferenceDeleterGuts() {
  DefaultDelete<int> delInt;
  IntDeleterRef id1(new int, delInt);

  IntDeleterRef id2(std::move(id1));
  CHECK(id1 == nullptr);
  CHECK(nullptr != id2);
  CHECK(&id1.get_deleter() == &id2.get_deleter());

  IntDeleterRef id3(std::move(id2));

  DefaultDelete<A> delA;
  ADeleterRef a1(new A, delA);
  a1.reset(nullptr);
  a1.reset(new B);
  a1 = nullptr;

  BDeleterRef b1(new B, delA);
  a1 = std::move(b1);

  BDeleterRef b2(new B, delA);

  ADeleterRef a2(std::move(b2));

  return true;
}

static bool TestReferenceDeleter() {
  gADestructorCalls = 0;
  gBDestructorCalls = 0;

  CHECK(TestReferenceDeleterGuts());

  CHECK(gADestructorCalls == 4);
  CHECK(gBDestructorCalls == 3);

  gADestructorCalls = 0;
  gBDestructorCalls = 0;
  return true;
}

typedef void (&FreeSignature)(void*);

static size_t DeleteIntFunctionCallCount = 0;

static void DeleteIntFunction(void* aPtr) {
  DeleteIntFunctionCallCount++;
  delete static_cast<int*>(aPtr);
}

static void SetMallocedInt(UniquePtr<int, FreeSignature>& aPtr, int aI) {
  int* newPtr = static_cast<int*>(malloc(sizeof(int)));
  *newPtr = aI;
  aPtr.reset(newPtr);
}

static UniquePtr<int, FreeSignature> MallocedInt(int aI) {
  UniquePtr<int, FreeSignature> ptr(static_cast<int*>(malloc(sizeof(int))),
                                    free);
  *ptr = aI;
  return ptr;
}
static bool TestFunctionReferenceDeleter() {
  // Look for allocator mismatches and leaks to verify these bits
  UniquePtr<int, FreeSignature> i1(MallocedInt(17));
  CHECK(*i1 == 17);

  SetMallocedInt(i1, 42);
  CHECK(*i1 == 42);

  // These bits use a custom deleter so we can instrument deletion.
  {
    UniquePtr<int, FreeSignature> i2 =
        UniquePtr<int, FreeSignature>(new int[42], DeleteIntFunction);
    CHECK(DeleteIntFunctionCallCount == 0);

    i2.reset(new int[76]);
    CHECK(DeleteIntFunctionCallCount == 1);
  }

  CHECK(DeleteIntFunctionCallCount == 2);

  return true;
}

template <typename T>
struct AppendNullptrTwice {
  AppendNullptrTwice() = default;

  bool operator()(Vector<T>& vec) {
    CHECK(vec.append(nullptr));
    CHECK(vec.append(nullptr));
    return true;
  }
};

static size_t AAfter;
static size_t BAfter;

static bool TestVectorGuts() {
  Vector<UniqueA> vec;
  CHECK(vec.append(new B));
  CHECK(vec.append(new A));
  CHECK(AppendNullptrTwice<UniqueA>()(vec));
  CHECK(vec.append(new B));

  size_t initialLength = vec.length();

  UniqueA* begin = vec.begin();
  bool appendA = true;
  do {
    CHECK(appendA ? vec.append(new A) : vec.append(new B));
    appendA = !appendA;
  } while (begin == vec.begin());

  size_t numAppended = vec.length() - initialLength;

  BAfter = numAppended / 2;
  AAfter = numAppended - numAppended / 2;

  CHECK(gADestructorCalls == 0);
  CHECK(gBDestructorCalls == 0);
  return true;
}

static bool TestVector() {
  gADestructorCalls = 0;
  gBDestructorCalls = 0;

  CHECK(TestVectorGuts());

  CHECK(gADestructorCalls == 3 + AAfter + BAfter);
  CHECK(gBDestructorCalls == 2 + BAfter);
  return true;
}

typedef UniquePtr<int[]> IntArray;
static_assert(sizeof(IntArray) == sizeof(int*), "stored most efficiently");

static bool TestArray() {
  static_assert(std::is_same_v<IntArray::DeleterType, DefaultDelete<int[]> >,
                "weird deleter?");

  IntArray n1(new int[5]);
  CHECK(n1);
  CHECK(n1.get() != nullptr);

  n1 = nullptr;
  CHECK(!n1);
  CHECK(n1.get() == nullptr);

  int* p1 = new int[42];
  n1.reset(p1);
  CHECK(n1);
  IntArray n2(std::move(n1));
  CHECK(!n1);
  CHECK(n1.get() == nullptr);
  CHECK(n2.get() == p1);

  std::swap(n1, n2);
  CHECK(n1.get() == p1);
  CHECK(n2.get() == nullptr);

  n1.swap(n2);
  CHECK(n1.get() == nullptr);
  CHECK(n2.get() == p1);
  delete[] n2.release();

  CHECK(n1.get() == nullptr);
  CHECK(n2.get() == nullptr);

  int* p2 = new int[7];
  int* p3 = new int[42];
  n1.reset(p2);
  n2.reset(p3);
  CHECK(n1.get() == p2);
  CHECK(n2.get() == p3);

  n1.swap(n2);
  CHECK(n2.get() == p2);
  CHECK(n1.get() == p3);

  n1 = std::move(n2);
  CHECK(n1.get() == p2);
  n1 = std::move(n2);
  CHECK(n1.get() == nullptr);

  UniquePtr<A[]> a1(new A[17]);
  static_assert(sizeof(a1) == sizeof(A*), "stored most efficiently");

  UniquePtr<A[]> a2(new A[5], DefaultDelete<A[]>());
  a2.reset(nullptr);
  a2.reset(new A[17]);
  a2 = nullptr;

  UniquePtr<A[]> a3(nullptr);
  a3.reset(new A[7]);

  return true;
}

struct Q {
  Q() = default;
  Q(const Q&) = default;

  Q(Q&, char) {}

  template <typename T>
  Q(Q, T&&, int) {}

  Q(intlongdoublevoid*) {}
};

static int randomInt() { return 4; }

static bool TestMakeUnique() {
  UniquePtr<int> a1(MakeUnique<int>());
  UniquePtr<long> a2(MakeUnique<long>(4));

  // no args, easy
  UniquePtr<Q> q0(MakeUnique<Q>());

  // temporary bound to const lval ref
  UniquePtr<Q> q1(MakeUnique<Q>(Q()));

  // passing through a non-const lval ref
  UniquePtr<Q> q2(MakeUnique<Q>(*q1, 'c'));

  // pass by copying, forward a temporary, pass by value
  UniquePtr<Q> q3(MakeUnique<Q>(Q(), UniquePtr<int>(), randomInt()));

  // various type mismatching to test "fuzzy" forwarding
  UniquePtr<Q> q4(MakeUnique<Q>('s', 66LL, 3.141592654, &q3));

  UniquePtr<char[]> c1(MakeUnique<char[]>(5));

  return true;
}

static bool TestVoid() {
  // UniquePtr<void> supports all operations except operator*() and
  // operator->().
  UniqueFreePtr<void> p1(malloc(1));
  UniqueFreePtr<void> p2;

  auto x = p1.get();
  CHECK(x != nullptr);
  CHECK((std::is_same_v<decltype(x), void*>));

  p2.reset(p1.release());
  CHECK(p1.get() == nullptr);
  CHECK(p2.get() != nullptr);

  p1 = std::move(p2);
  CHECK(p1);
  CHECK(!p2);

  p1.swap(p2);
  CHECK(!p1);
  CHECK(p2);

  p2 = nullptr;
  CHECK(!p2);

  return true;
}

static bool TestTempPtrToSetter() {
  static int sFooRefcount = 0;
  struct Foo {
    Foo() { sFooRefcount += 1; }

    ~Foo() { sFooRefcount -= 1; }
  };

  const auto AllocByOutvar = [](Foo** out) -> bool {
    *out = new Foo;
    return true;
  };

  {
    UniquePtr<Foo> f;
    (void)AllocByOutvar(mozilla::TempPtrToSetter(&f));
    CHECK(sFooRefcount == 1);
  }
  CHECK(sFooRefcount == 0);

  {
    std::unique_ptr<Foo> f;
    (void)AllocByOutvar(mozilla::TempPtrToSetter(&f));
    CHECK(sFooRefcount == 1);
  }
  CHECK(sFooRefcount == 0);

  return true;
}

int main() {
  TestDeleterType();

  if (!TestDefaultFree()) {
    return 1;
  }
  if (!TestFreeClass()) {
    return 1;
  }
  if (!TestReferenceDeleter()) {
    return 1;
  }
  if (!TestFunctionReferenceDeleter()) {
    return 1;
  }
  if (!TestVector()) {
    return 1;
  }
  if (!TestArray()) {
    return 1;
  }
  if (!TestMakeUnique()) {
    return 1;
  }
  if (!TestVoid()) {
    return 1;
  }
  if (!TestTempPtrToSetter()) {
    return 1;
  }
  return 0;
}

98%


¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.