15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/debug/leak_annotations.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class T>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OffThreadObjectCreator {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static T* NewObject() {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    T* result;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Thread creator_thread("creator_thread");
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      creator_thread.Start();
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      creator_thread.message_loop()->PostTask(
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(OffThreadObjectCreator::CreateObject, &result));
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(result);  // We synchronized on thread destruction above.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void CreateObject(T** result) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = new T;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Base {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string member;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct Derived : public Base {};
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct TargetBase {};
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct Target : public TargetBase, public SupportsWeakPtr<Target> {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~Target() {}
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct DerivedTarget : public Target {};
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Arrow {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<Target> target;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)struct TargetWithFactory : public Target {
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  TargetWithFactory() : factory(this) {}
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  WeakPtrFactory<Target> factory;
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)};
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class to create and destroy weak pointer copies
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and delete objects on a background thread.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BackgroundThread : public Thread {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread() : Thread("owner_thread") {}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~BackgroundThread() {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stop();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CreateArrowFromTarget(Arrow** arrow, Target* target) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitableEvent completion(true, false);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop()->PostTask(
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BackgroundThread::DoCreateArrowFromTarget,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   arrow, target, &completion));
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion.Wait();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitableEvent completion(true, false);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop()->PostTask(
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BackgroundThread::DoCreateArrowFromArrow,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   arrow, other, &completion));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion.Wait();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DeleteTarget(Target* object) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitableEvent completion(true, false);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop()->PostTask(
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion.Wait();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void CopyAndAssignArrow(Arrow* object) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WaitableEvent completion(true, false);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop()->PostTask(
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&BackgroundThread::DoCopyAndAssignArrow,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   object, &completion));
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    completion.Wait();
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void CopyAndAssignArrowBase(Arrow* object) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WaitableEvent completion(true, false);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop()->PostTask(
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   object, &completion));
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    completion.Wait();
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DeleteArrow(Arrow* object) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitableEvent completion(true, false);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop()->PostTask(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion.Wait();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target* DeRef(const Arrow* arrow) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitableEvent completion(true, false);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Target* result = NULL;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_loop()->PostTask(
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion.Wait();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void DoCreateArrowFromArrow(Arrow** arrow,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const Arrow* other,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     WaitableEvent* completion) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *arrow = new Arrow;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    **arrow = *other;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion->Signal();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void DoCreateArrowFromTarget(Arrow** arrow,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      Target* target,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      WaitableEvent* completion) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *arrow = new Arrow;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*arrow)->target = target->AsWeakPtr();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion->Signal();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void DoDeRef(const Arrow* arrow,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      Target** result,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      WaitableEvent* completion) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = arrow->target.get();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion->Signal();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void DoDeleteTarget(Target* object, WaitableEvent* completion) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete object;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion->Signal();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Copy constructor.
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Arrow a = *object;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Assignment operator.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *object = a;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    completion->Signal();
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static void DoCopyAndAssignArrowBase(
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Arrow* object,
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WaitableEvent* completion) {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Copy constructor.
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WeakPtr<TargetBase> b = object->target;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Assignment operator.
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WeakPtr<TargetBase> c;
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = object->target;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    completion->Signal();
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete object;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    completion->Signal();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrFactoryTest, Basic) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int data;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtrFactory<int> factory(&data);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<int> ptr = factory.GetWeakPtr();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(&data, ptr.get());
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrFactoryTest, Comparison) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int data;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtrFactory<int> factory(&data);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<int> ptr = factory.GetWeakPtr();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<int> ptr2 = ptr;
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ptr.get(), ptr2.get());
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrFactoryTest, OutOfScope) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<int> ptr;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL, ptr.get());
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int data;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WeakPtrFactory<int> factory(&data);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ptr = factory.GetWeakPtr();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL, ptr.get());
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrFactoryTest, Multiple) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<int> a, b;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int data;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WeakPtrFactory<int> factory(&data);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a = factory.GetWeakPtr();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    b = factory.GetWeakPtr();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(&data, a.get());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(&data, b.get());
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL, a.get());
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL, b.get());
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrFactoryTest, MultipleStaged) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<int> a;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int data;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WeakPtrFactory<int> factory(&data);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    a = factory.GetWeakPtr();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WeakPtr<int> b = factory.GetWeakPtr();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(NULL != a.get());
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL, a.get());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrFactoryTest, Dereference) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Base data;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data.member = "123456";
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtrFactory<Base> factory(&data);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<Base> ptr = factory.GetWeakPtr();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(&data, ptr.get());
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data.member, (*ptr).member);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(data.member, ptr->member);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrFactoryTest, UpCast) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Derived data;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtrFactory<Derived> factory(&data);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<Base> ptr = factory.GetWeakPtr();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ptr = factory.GetWeakPtr();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(ptr.get(), &data);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, SupportsWeakPtr) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target target;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<Target> ptr = target.AsWeakPtr();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(&target, ptr.get());
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, DerivedTarget) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DerivedTarget target;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(&target, ptr.get());
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, InvalidateWeakPtrs) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int data;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtrFactory<int> factory(&data);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<int> ptr = factory.GetWeakPtr();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(&data, ptr.get());
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(factory.HasWeakPtrs());
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  factory.InvalidateWeakPtrs();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL, ptr.get());
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(factory.HasWeakPtrs());
280116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
281116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Test that the factory can create new weak pointers after a
282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // InvalidateWeakPtrs call, and they remain valid until the next
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // InvalidateWeakPtrs call.
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  WeakPtr<int> ptr2 = factory.GetWeakPtr();
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_EQ(&data, ptr2.get());
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_TRUE(factory.HasWeakPtrs());
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  factory.InvalidateWeakPtrs();
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_EQ(NULL, ptr2.get());
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_FALSE(factory.HasWeakPtrs());
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, HasWeakPtrs) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int data;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtrFactory<int> factory(&data);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WeakPtr<int> ptr = factory.GetWeakPtr();
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(factory.HasWeakPtrs());
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(factory.HasWeakPtrs());
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test that it is OK to create an object that supports WeakPtr on one thread,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but use it on another.  This tests that we do not trip runtime checks that
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ensure that a WeakPtr is not used by multiple threads.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject());
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakPtr<Target> weak_ptr = target->AsWeakPtr();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(target.get(), weak_ptr.get());
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test that it is OK to create an object that has a WeakPtr member on one
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread, but use it on another.  This tests that we do not trip runtime
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // checks that ensure that a WeakPtr is not used by multiple threads.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject());
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target target;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arrow->target = target.AsWeakPtr();
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(&target, arrow->target.get());
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, MoveOwnershipImplicitly) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move object ownership to another thread by releasing all weak pointers
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on the original thread first, and then establish WeakPtr on a different
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread.
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target* target = new Target();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WeakPtr<Target> weak_ptr = target->AsWeakPtr();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Main thread deletes the WeakPtr, then the thread ownership of the
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // object can be implicitly moved.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow* arrow;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Background thread creates WeakPtr(and implicitly owns the object).
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.CreateArrowFromTarget(&arrow, target);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(background.DeRef(arrow), target);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Main thread creates another WeakPtr, but this does not trigger implicitly
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // thread ownership move.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Arrow arrow;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arrow.target = target->AsWeakPtr();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The new WeakPtr is owned by background thread.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(target, background.DeRef(&arrow));
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Target can only be deleted on background thread.
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.DeleteTarget(target);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.DeleteArrow(arrow);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow* arrow;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Target target;
362a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Background thread creates WeakPtr.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    background.CreateArrowFromTarget(&arrow, &target);
364a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
365a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Bind to background thread.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(&target, background.DeRef(arrow));
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
368a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Release the only WeakPtr.
369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    arrow->target.reset();
370a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
371a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Now we should be able to create a new reference from this thread.
372a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    arrow->target = target.AsWeakPtr();
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Re-bind to main thread.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(&target, arrow->target.get());
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
377a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // And the main thread can now delete the target.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
380a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  delete arrow;
381a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
382a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
383a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) {
384a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  BackgroundThread background;
385a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  background.Start();
386a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
387a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Arrow arrow;
388a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  scoped_ptr<TargetWithFactory> target(new TargetWithFactory);
389a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
390a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Bind to main thread.
391a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  arrow.target = target->factory.GetWeakPtr();
392a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  EXPECT_EQ(target.get(), arrow.target.get());
393a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
394a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  target->factory.InvalidateWeakPtrs();
395a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  EXPECT_EQ(NULL, arrow.target.get());
396a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
397a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  arrow.target = target->factory.GetWeakPtr();
398a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Re-bind to background thread.
399a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  EXPECT_EQ(target.get(), background.DeRef(&arrow));
400a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
401a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // And the background thread can now delete the target.
402a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  background.DeleteTarget(target.release());
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Originating thread has a WeakPtr that outlives others.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Main thread creates a WeakPtr
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Background thread creates a WeakPtr copy from the one in main thread
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Destruct the WeakPtr on background thread
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Destruct the WeakPtr on main thread
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target target;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow arrow;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arrow.target = target.AsWeakPtr();
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow* arrow_copy;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.CreateArrowFromArrow(&arrow_copy, &arrow);
420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(arrow_copy->target.get(), &target);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.DeleteArrow(arrow_copy);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Originating thread drops all references before another thread.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Main thread creates a WeakPtr and passes copy to background thread
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Destruct the pointer on main thread
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Destruct the pointer on background thread
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target target;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow* arrow_copy;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Arrow arrow;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arrow.target = target.AsWeakPtr();
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    background.CreateArrowFromArrow(&arrow_copy, &arrow);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
439868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(arrow_copy->target.get(), &target);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.DeleteArrow(arrow_copy);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, OwnerThreadDeletesObject) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Originating thread invalidates WeakPtrs while its held by other thread.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Main thread creates WeakPtr and passes Copy to background thread
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - Object gets destroyed on main thread
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   (invalidates WeakPtr on background thread)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - WeakPtr gets destroyed on Thread B
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow* arrow_copy;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Target target;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Arrow arrow;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arrow.target = target.AsWeakPtr();
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    background.CreateArrowFromArrow(&arrow_copy, &arrow);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(NULL, arrow_copy->target.get());
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.DeleteArrow(arrow_copy);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) {
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Main thread creates a Target object.
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Target target;
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Main thread creates an arrow referencing the Target.
466868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Arrow *arrow = new Arrow();
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  arrow->target = target.AsWeakPtr();
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Background can copy and assign arrow (as well as the WeakPtr inside).
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BackgroundThread background;
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background.Start();
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background.CopyAndAssignArrow(arrow);
473868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  background.DeleteArrow(arrow);
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) {
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Main thread creates a Target object.
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Target target;
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Main thread creates an arrow referencing the Target.
480868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Arrow *arrow = new Arrow();
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  arrow->target = target.AsWeakPtr();
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Background can copy and assign arrow's WeakPtr to a base class WeakPtr.
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BackgroundThread background;
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background.Start();
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background.CopyAndAssignArrowBase(arrow);
487868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  background.DeleteArrow(arrow);
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Main thread creates a Target object.
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target target;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Main thread creates an arrow referencing the Target.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow* arrow = new Arrow();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arrow->target = target.AsWeakPtr();
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Background can delete arrow (as well as the WeakPtr inside).
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.DeleteArrow(arrow);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The default style "fast" does not support multi-threaded tests
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (introduces deadlock on Linux).
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Main thread creates a Target object.
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target target;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Main thread creates an arrow referencing the Target.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow arrow;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arrow.target = target.AsWeakPtr();
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Background copies the WeakPtr.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow* arrow_copy;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.CreateArrowFromArrow(&arrow_copy, &arrow);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The copy is still bound to main thread so I can deref.
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(arrow.target.get(), arrow_copy->target.get());
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Although background thread created the copy, it can not deref the copied
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WeakPtr.
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_DEATH(background.DeRef(arrow_copy), "");
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.DeleteArrow(arrow_copy);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The default style "fast" does not support multi-threaded tests
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (introduces deadlock on Linux).
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Main thread creates a Target object.
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Target target;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Main thread creates an arrow referencing the Target (so target's
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread ownership can not be implicitly moved).
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow arrow;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arrow.target = target.AsWeakPtr();
54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  arrow.target.get();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Background thread tries to deref target, which violates thread ownership.
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_DEATH(background.DeRef(&arrow), "");
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The default style "fast" does not support multi-threaded tests
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (introduces deadlock on Linux).
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Target> target(new Target());
55990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Main thread creates an arrow referencing the Target.
56190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Arrow arrow;
56290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  arrow.target = target->AsWeakPtr();
56390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Background thread tries to deref target, binding it to the thread.
56590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  BackgroundThread background;
56690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  background.Start();
56790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  background.DeRef(&arrow);
56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
56990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Main thread deletes Target, violating thread binding.
570868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ASSERT_DEATH(target.reset(), "");
571868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
572868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // |target.reset()| died so |target| still holds the object, so we
573868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // must pass it to the background thread to teardown.
574868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  background.DeleteTarget(target.release());
57590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
57690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
57790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) {
57890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The default style "fast" does not support multi-threaded tests
57990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // (introduces deadlock on Linux).
58090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
58190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
58290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<Target> target(new Target());
58390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
58490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Main thread creates an arrow referencing the Target, and references it, so
58590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // that it becomes bound to the thread.
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Arrow arrow;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arrow.target = target->AsWeakPtr();
58890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  arrow.target.get();
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Background thread tries to delete target, volating thread binding.
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BackgroundThread background;
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  background.Start();
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_DEATH(background.DeleteTarget(target.release()), "");
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
59790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // The default style "fast" does not support multi-threaded tests
59890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // (introduces deadlock on Linux).
59990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
60090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
60190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<Target> target(new Target());
60290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
60390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Main thread creates an arrow referencing the Target.
60490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Arrow arrow;
60590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  arrow.target = target->AsWeakPtr();
60690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
60790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Background thread tries to delete target, binding the object to the thread.
60890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  BackgroundThread background;
60990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  background.Start();
61090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  background.DeleteTarget(target.release());
61190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
61290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Main thread attempts to dereference the target, violating thread binding.
61390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_DEATH(arrow.target.get(), "");
61490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
61590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
619