| File: | var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/ipc/ByteBuf.h |
| Warning: | line 61, column 16 Attempt to free released memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* vim:set ts=2 sw=2 sts=2 cin et: */ | |||
| 2 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
| 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
| 5 | ||||
| 6 | #include "nsIconChannel.h" | |||
| 7 | ||||
| 8 | #include <stdlib.h> | |||
| 9 | #include <unistd.h> | |||
| 10 | ||||
| 11 | #include "mozilla/DebugOnly.h" | |||
| 12 | #include "mozilla/EndianUtils.h" | |||
| 13 | #include "mozilla/NullPrincipal.h" | |||
| 14 | #include "mozilla/CheckedInt.h" | |||
| 15 | #include "mozilla/dom/ContentChild.h" | |||
| 16 | #include "mozilla/gfx/Swizzle.h" | |||
| 17 | #include "mozilla/ipc/ByteBuf.h" | |||
| 18 | #include <algorithm> | |||
| 19 | ||||
| 20 | #include <gio/gio.h> | |||
| 21 | #include <gio/gdesktopappinfo.h> | |||
| 22 | ||||
| 23 | #include <gtk/gtk.h> | |||
| 24 | ||||
| 25 | #include "nsMimeTypes.h" | |||
| 26 | #include "nsIMIMEService.h" | |||
| 27 | ||||
| 28 | #include "nsServiceManagerUtils.h" | |||
| 29 | ||||
| 30 | #include "nsNetUtil.h" | |||
| 31 | #include "nsComponentManagerUtils.h" | |||
| 32 | #include "nsIStringStream.h" | |||
| 33 | #include "nsServiceManagerUtils.h" | |||
| 34 | #include "nsIURL.h" | |||
| 35 | #include "nsIPipe.h" | |||
| 36 | #include "nsIAsyncInputStream.h" | |||
| 37 | #include "nsIAsyncOutputStream.h" | |||
| 38 | #include "prlink.h" | |||
| 39 | #include "gfxPlatform.h" | |||
| 40 | ||||
| 41 | using mozilla::CheckedInt32; | |||
| 42 | using mozilla::ipc::ByteBuf; | |||
| 43 | ||||
| 44 | NS_IMPL_ISUPPORTS(nsIconChannel, nsIRequest, nsIChannel)MozExternalRefCountType nsIconChannel::AddRef(void) { static_assert (!std::is_destructible_v<nsIconChannel>, "Reference-counted class " "nsIconChannel" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 44); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 44; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsIconChannel" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsIconChannel" != nullptr)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsIconChannel\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 44); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsIconChannel\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 44; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("nsIconChannel" " not thread-safe"); nsrefcnt count = ++mRefCnt ; NS_LogAddRef((this), (count), ("nsIconChannel"), (uint32_t) (sizeof(*this))); return count; } MozExternalRefCountType nsIconChannel ::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 44); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 44 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsIconChannel" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsIconChannel" != nullptr)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsIconChannel\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 44); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsIconChannel\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 44; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("nsIconChannel" " not thread-safe"); const char* const nametmp = "nsIconChannel"; nsrefcnt count = --mRefCnt; NS_LogRelease ((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsIconChannel:: QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 44); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsIconChannel, nsIRequest>, int32_t( reinterpret_cast <char*>(static_cast<nsIRequest*>((nsIconChannel*) 0x1000)) - reinterpret_cast<char*>((nsIconChannel*)0x1000 ))}, {&mozilla::detail::kImplementedIID<nsIconChannel, nsIChannel>, int32_t( reinterpret_cast<char*>(static_cast <nsIChannel*>((nsIconChannel*)0x1000)) - reinterpret_cast <char*>((nsIconChannel*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsIconChannel, nsISupports>, int32_t( reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIRequest*>((nsIconChannel*)0x1000))) - reinterpret_cast <char*>((nsIconChannel*)0x1000))}, { nullptr, 0 } } ; static_assert (std::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } | |||
| 45 | ||||
| 46 | static nsresult MozGdkPixbufToByteBuf(GdkPixbuf* aPixbuf, ByteBuf* aByteBuf) { | |||
| 47 | int width = gdk_pixbuf_get_width(aPixbuf); | |||
| 48 | int height = gdk_pixbuf_get_height(aPixbuf); | |||
| 49 | NS_ENSURE_TRUE(height < 256 && width < 256 && height > 0 && width > 0 &&do { if ((__builtin_expect(!!(!(height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha (aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4) ), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha(aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 54); return NS_ERROR_UNEXPECTED; } } while (false) | |||
| 50 | gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB &&do { if ((__builtin_expect(!!(!(height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha (aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4) ), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha(aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 54); return NS_ERROR_UNEXPECTED; } } while (false) | |||
| 51 | gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 &&do { if ((__builtin_expect(!!(!(height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha (aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4) ), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha(aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 54); return NS_ERROR_UNEXPECTED; } } while (false) | |||
| 52 | gdk_pixbuf_get_has_alpha(aPixbuf) &&do { if ((__builtin_expect(!!(!(height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha (aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4) ), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha(aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 54); return NS_ERROR_UNEXPECTED; } } while (false) | |||
| 53 | gdk_pixbuf_get_n_channels(aPixbuf) == 4,do { if ((__builtin_expect(!!(!(height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha (aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4) ), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha(aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 54); return NS_ERROR_UNEXPECTED; } } while (false) | |||
| 54 | NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha (aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4) ), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "height < 256 && width < 256 && height > 0 && width > 0 && gdk_pixbuf_get_colorspace(aPixbuf) == GDK_COLORSPACE_RGB && gdk_pixbuf_get_bits_per_sample(aPixbuf) == 8 && gdk_pixbuf_get_has_alpha(aPixbuf) && gdk_pixbuf_get_n_channels(aPixbuf) == 4" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 54); return NS_ERROR_UNEXPECTED; } } while (false); | |||
| 55 | ||||
| 56 | const int n_channels = 4; | |||
| 57 | CheckedInt32 buf_size = | |||
| 58 | 4 + n_channels * CheckedInt32(height) * CheckedInt32(width); | |||
| 59 | if (!buf_size.isValid()) { | |||
| 60 | return NS_ERROR_OUT_OF_MEMORY; | |||
| 61 | } | |||
| 62 | uint8_t* const buf = (uint8_t*)moz_xmalloc(buf_size.value()); | |||
| 63 | uint8_t* out = buf; | |||
| 64 | ||||
| 65 | *(out++) = width; | |||
| 66 | *(out++) = height; | |||
| 67 | *(out++) = uint8_t(mozilla::gfx::SurfaceFormat::OS_RGBA); | |||
| 68 | ||||
| 69 | // Set all bits to ensure in nsIconDecoder we color manage and premultiply. | |||
| 70 | *(out++) = 0xFF; | |||
| 71 | ||||
| 72 | const guchar* const pixels = gdk_pixbuf_get_pixels(aPixbuf); | |||
| 73 | int instride = gdk_pixbuf_get_rowstride(aPixbuf); | |||
| 74 | int outstride = width * n_channels; | |||
| 75 | ||||
| 76 | // encode the RGB data and the A data and adjust the stride as necessary. | |||
| 77 | mozilla::gfx::SwizzleData(pixels, instride, | |||
| 78 | mozilla::gfx::SurfaceFormat::R8G8B8A8, out, | |||
| 79 | outstride, mozilla::gfx::SurfaceFormat::OS_RGBA, | |||
| 80 | mozilla::gfx::IntSize(width, height)); | |||
| 81 | ||||
| 82 | *aByteBuf = ByteBuf(buf, buf_size.value(), buf_size.value()); | |||
| 83 | return NS_OK; | |||
| 84 | } | |||
| 85 | ||||
| 86 | static nsresult ByteBufToStream(ByteBuf&& aBuf, nsIInputStream** aStream) { | |||
| 87 | nsresult rv; | |||
| 88 | nsCOMPtr<nsIStringInputStream> stream = | |||
| 89 | do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); | |||
| 90 | ||||
| 91 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 91)) { | |||
| 92 | return rv; | |||
| 93 | } | |||
| 94 | ||||
| 95 | // stream takes ownership of buf and will free it on destruction. | |||
| 96 | // This function cannot fail. | |||
| 97 | rv = stream->AdoptData(reinterpret_cast<char*>(aBuf.mData), aBuf.mLen); | |||
| 98 | MOZ_ASSERT(CheckedInt32(aBuf.mLen).isValid(),do { static_assert( mozilla::detail::AssertionConditionType< decltype(CheckedInt32(aBuf.mLen).isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(CheckedInt32(aBuf.mLen).isValid ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("CheckedInt32(aBuf.mLen).isValid()" " (" "aBuf.mLen should fit in int32_t" ")", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 99); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CheckedInt32(aBuf.mLen).isValid()" ") (" "aBuf.mLen should fit in int32_t" ")"); do { *((volatile int*)__null) = 99; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) | |||
| 99 | "aBuf.mLen should fit in int32_t")do { static_assert( mozilla::detail::AssertionConditionType< decltype(CheckedInt32(aBuf.mLen).isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(CheckedInt32(aBuf.mLen).isValid ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("CheckedInt32(aBuf.mLen).isValid()" " (" "aBuf.mLen should fit in int32_t" ")", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 99); AnnotateMozCrashReason("MOZ_ASSERT" "(" "CheckedInt32(aBuf.mLen).isValid()" ") (" "aBuf.mLen should fit in int32_t" ")"); do { *((volatile int*)__null) = 99; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); | |||
| 100 | aBuf.mData = nullptr; | |||
| 101 | ||||
| 102 | // If this no longer holds then re-examine buf's lifetime. | |||
| 103 | MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ")"); do { *((volatile int*)__null) = 103; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 104 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 104); return rv; } } while (false); | |||
| 105 | ||||
| 106 | stream.forget(aStream); | |||
| 107 | return NS_OK; | |||
| 108 | } | |||
| 109 | ||||
| 110 | static nsresult StreamToChannel(already_AddRefed<nsIInputStream> aStream, | |||
| 111 | nsIURI* aURI, nsIChannel** aChannel) { | |||
| 112 | // nsIconProtocolHandler::NewChannel will provide the correct loadInfo for | |||
| 113 | // this iconChannel. Use the most restrictive security settings for the | |||
| 114 | // temporary loadInfo to make sure the channel can not be opened. | |||
| 115 | nsCOMPtr<nsIPrincipal> nullPrincipal = | |||
| 116 | mozilla::NullPrincipal::CreateWithoutOriginAttributes(); | |||
| 117 | return NS_NewInputStreamChannel( | |||
| 118 | aChannel, aURI, std::move(aStream), nullPrincipal, | |||
| 119 | nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED, | |||
| 120 | nsIContentPolicy::TYPE_INTERNAL_IMAGE, nsLiteralCString(IMAGE_ICON_MS"image/icon")); | |||
| 121 | } | |||
| 122 | ||||
| 123 | static GtkWidget* gProtoWindow = nullptr; | |||
| 124 | static GtkWidget* gStockImageWidget = nullptr; | |||
| 125 | ||||
| 126 | static void ensure_stock_image_widget() { | |||
| 127 | // Only the style of the GtkImage needs to be used, but the widget is kept | |||
| 128 | // to track dynamic style changes. | |||
| 129 | if (!gProtoWindow) { | |||
| 130 | gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP); | |||
| 131 | GtkWidget* protoLayout = gtk_fixed_new(); | |||
| 132 | gtk_container_add(GTK_CONTAINER(gProtoWindow)((((GtkContainer*) (void *) ((gProtoWindow))))), protoLayout); | |||
| 133 | ||||
| 134 | gStockImageWidget = gtk_image_new(); | |||
| 135 | gtk_container_add(GTK_CONTAINER(protoLayout)((((GtkContainer*) (void *) ((protoLayout))))), gStockImageWidget); | |||
| 136 | ||||
| 137 | gtk_widget_ensure_style(gStockImageWidget); | |||
| 138 | } | |||
| 139 | } | |||
| 140 | ||||
| 141 | static GtkIconSize moz_gtk_icon_size(const char* name) { | |||
| 142 | if (strcmp(name, "button") == 0) { | |||
| 143 | return GTK_ICON_SIZE_BUTTON; | |||
| 144 | } | |||
| 145 | ||||
| 146 | if (strcmp(name, "menu") == 0) { | |||
| 147 | return GTK_ICON_SIZE_MENU; | |||
| 148 | } | |||
| 149 | ||||
| 150 | if (strcmp(name, "toolbar") == 0) { | |||
| 151 | return GTK_ICON_SIZE_LARGE_TOOLBAR; | |||
| 152 | } | |||
| 153 | ||||
| 154 | if (strcmp(name, "toolbarsmall") == 0) { | |||
| 155 | return GTK_ICON_SIZE_SMALL_TOOLBAR; | |||
| 156 | } | |||
| 157 | ||||
| 158 | if (strcmp(name, "dnd") == 0) { | |||
| 159 | return GTK_ICON_SIZE_DND; | |||
| 160 | } | |||
| 161 | ||||
| 162 | if (strcmp(name, "dialog") == 0) { | |||
| 163 | return GTK_ICON_SIZE_DIALOG; | |||
| 164 | } | |||
| 165 | ||||
| 166 | return GTK_ICON_SIZE_MENU; | |||
| 167 | } | |||
| 168 | ||||
| 169 | static int32_t GetIconSize(nsIMozIconURI* aIconURI) { | |||
| 170 | nsAutoCString iconSizeString; | |||
| 171 | ||||
| 172 | aIconURI->GetIconSize(iconSizeString); | |||
| 173 | if (iconSizeString.IsEmpty()) { | |||
| 174 | uint32_t size; | |||
| 175 | mozilla::DebugOnly<nsresult> rv = aIconURI->GetImageSize(&size); | |||
| 176 | NS_ASSERTION(NS_SUCCEEDED(rv), "GetImageSize failed")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1 ))))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "GetImageSize failed" , "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 176); MOZ_PretendNoReturn(); } } while (0); | |||
| 177 | return size; | |||
| 178 | } | |||
| 179 | int size; | |||
| 180 | ||||
| 181 | GtkIconSize icon_size = moz_gtk_icon_size(iconSizeString.get()); | |||
| 182 | gtk_icon_size_lookup(icon_size, &size, nullptr); | |||
| 183 | return size; | |||
| 184 | } | |||
| 185 | ||||
| 186 | /* Scale icon buffer to preferred size */ | |||
| 187 | static nsresult ScaleIconBuf(GdkPixbuf** aBuf, int32_t iconSize) { | |||
| 188 | // Scale buffer only if width or height differ from preferred size | |||
| 189 | if (gdk_pixbuf_get_width(*aBuf) != iconSize && | |||
| 190 | gdk_pixbuf_get_height(*aBuf) != iconSize) { | |||
| 191 | GdkPixbuf* scaled = | |||
| 192 | gdk_pixbuf_scale_simple(*aBuf, iconSize, iconSize, GDK_INTERP_BILINEAR); | |||
| 193 | // replace original buffer by scaled | |||
| 194 | g_object_unref(*aBuf); | |||
| 195 | *aBuf = scaled; | |||
| 196 | if (!scaled) { | |||
| 197 | return NS_ERROR_OUT_OF_MEMORY; | |||
| 198 | } | |||
| 199 | } | |||
| 200 | return NS_OK; | |||
| 201 | } | |||
| 202 | ||||
| 203 | /* static */ | |||
| 204 | nsresult nsIconChannel::GetIconWithGIO(nsIMozIconURI* aIconURI, | |||
| 205 | ByteBuf* aDataOut) { | |||
| 206 | GIcon* icon = nullptr; | |||
| 207 | nsCOMPtr<nsIURL> fileURI; | |||
| 208 | ||||
| 209 | // Read icon content | |||
| 210 | aIconURI->GetIconURL(getter_AddRefs(fileURI)); | |||
| 211 | ||||
| 212 | // Get icon for file specified by URI | |||
| 213 | if (fileURI) { | |||
| 214 | nsAutoCString spec; | |||
| 215 | fileURI->GetAsciiSpec(spec); | |||
| 216 | if (fileURI->SchemeIs("file")) { | |||
| 217 | GFile* file = g_file_new_for_uri(spec.get()); | |||
| 218 | GFileInfo* fileInfo = | |||
| 219 | g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_ICON"standard::icon", | |||
| 220 | G_FILE_QUERY_INFO_NONE, nullptr, nullptr); | |||
| 221 | g_object_unref(file); | |||
| 222 | if (fileInfo) { | |||
| 223 | // icon from g_content_type_get_icon doesn't need unref | |||
| 224 | icon = g_file_info_get_icon(fileInfo); | |||
| 225 | if (icon) { | |||
| 226 | g_object_ref(icon); | |||
| 227 | } | |||
| 228 | g_object_unref(fileInfo); | |||
| 229 | } | |||
| 230 | } | |||
| 231 | } else { | |||
| 232 | // From the moz-icon://appId?size=... get the appId | |||
| 233 | nsAutoCString appId; | |||
| 234 | aIconURI->GetAsciiSpec(appId); | |||
| 235 | ||||
| 236 | if (appId.Find("?size=")) { | |||
| 237 | appId.Truncate(appId.Find("?size=")); | |||
| 238 | } | |||
| 239 | ||||
| 240 | appId = Substring(appId, sizeof("moz-icon:/")); | |||
| 241 | ||||
| 242 | GDesktopAppInfo* app_info = g_desktop_app_info_new(appId.get()); | |||
| 243 | if (app_info) { | |||
| 244 | icon = g_app_info_get_icon((GAppInfo*)app_info); | |||
| 245 | if (icon) { | |||
| 246 | g_object_ref(icon); | |||
| 247 | } | |||
| 248 | g_object_unref(app_info); | |||
| 249 | } | |||
| 250 | } | |||
| 251 | ||||
| 252 | // Try to get icon by using MIME type | |||
| 253 | if (!icon) { | |||
| 254 | nsAutoCString type; | |||
| 255 | aIconURI->GetContentType(type); | |||
| 256 | // Try to get MIME type from file extension by using nsIMIMEService | |||
| 257 | if (type.IsEmpty()) { | |||
| 258 | nsCOMPtr<nsIMIMEService> ms(do_GetService("@mozilla.org/mime;1")); | |||
| 259 | if (ms) { | |||
| 260 | nsAutoCString fileExt; | |||
| 261 | aIconURI->GetFileExtension(fileExt); | |||
| 262 | ms->GetTypeFromExtension(fileExt, type); | |||
| 263 | } | |||
| 264 | } | |||
| 265 | char* ctype = nullptr; // character representation of content type | |||
| 266 | if (!type.IsEmpty()) { | |||
| 267 | ctype = g_content_type_from_mime_type(type.get()); | |||
| 268 | } | |||
| 269 | if (ctype) { | |||
| 270 | icon = g_content_type_get_icon(ctype); | |||
| 271 | g_free(ctype); | |||
| 272 | } | |||
| 273 | } | |||
| 274 | ||||
| 275 | // Get default icon theme | |||
| 276 | GtkIconTheme* iconTheme = gtk_icon_theme_get_default(); | |||
| 277 | GtkIconInfo* iconInfo = nullptr; | |||
| 278 | // Get icon size | |||
| 279 | int32_t iconSize = GetIconSize(aIconURI); | |||
| 280 | ||||
| 281 | if (icon) { | |||
| 282 | // Use icon and theme to get GtkIconInfo | |||
| 283 | iconInfo = gtk_icon_theme_lookup_by_gicon(iconTheme, icon, iconSize, | |||
| 284 | (GtkIconLookupFlags)0); | |||
| 285 | g_object_unref(icon); | |||
| 286 | } | |||
| 287 | ||||
| 288 | if (!iconInfo) { | |||
| 289 | // Mozilla's mimetype lookup failed. Try the "unknown" icon. | |||
| 290 | iconInfo = gtk_icon_theme_lookup_icon(iconTheme, "unknown", iconSize, | |||
| 291 | (GtkIconLookupFlags)0); | |||
| 292 | if (!iconInfo) { | |||
| 293 | return NS_ERROR_NOT_AVAILABLE; | |||
| 294 | } | |||
| 295 | } | |||
| 296 | ||||
| 297 | // Create a GdkPixbuf buffer containing icon and scale it | |||
| 298 | GdkPixbuf* buf = gtk_icon_info_load_icon(iconInfo, nullptr); | |||
| 299 | gtk_icon_info_free(iconInfo); | |||
| 300 | if (!buf) { | |||
| 301 | return NS_ERROR_UNEXPECTED; | |||
| 302 | } | |||
| 303 | ||||
| 304 | nsresult rv = ScaleIconBuf(&buf, iconSize); | |||
| 305 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 305); return rv; } } while (false); | |||
| 306 | ||||
| 307 | rv = MozGdkPixbufToByteBuf(buf, aDataOut); | |||
| 308 | g_object_unref(buf); | |||
| 309 | return rv; | |||
| 310 | } | |||
| 311 | ||||
| 312 | /* static */ | |||
| 313 | nsresult nsIconChannel::GetIcon(nsIURI* aURI, ByteBuf* aDataOut) { | |||
| 314 | nsCOMPtr<nsIMozIconURI> iconURI = do_QueryInterface(aURI); | |||
| 315 | NS_ASSERTION(iconURI, "URI is not an nsIMozIconURI")do { if (!(iconURI)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "URI is not an nsIMozIconURI" , "iconURI", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 315); MOZ_PretendNoReturn(); } } while (0); | |||
| 316 | ||||
| 317 | if (!iconURI) { | |||
| 318 | return NS_ERROR_NOT_AVAILABLE; | |||
| 319 | } | |||
| 320 | ||||
| 321 | if (gfxPlatform::IsHeadless()) { | |||
| 322 | return NS_ERROR_NOT_AVAILABLE; | |||
| 323 | } | |||
| 324 | ||||
| 325 | nsAutoCString stockIcon; | |||
| 326 | iconURI->GetStockIcon(stockIcon); | |||
| 327 | if (stockIcon.IsEmpty()) { | |||
| 328 | return GetIconWithGIO(iconURI, aDataOut); | |||
| 329 | } | |||
| 330 | ||||
| 331 | // Search for stockIcon | |||
| 332 | nsAutoCString iconSizeString; | |||
| 333 | iconURI->GetIconSize(iconSizeString); | |||
| 334 | ||||
| 335 | nsAutoCString iconStateString; | |||
| 336 | iconURI->GetIconState(iconStateString); | |||
| 337 | ||||
| 338 | GtkIconSize icon_size = moz_gtk_icon_size(iconSizeString.get()); | |||
| 339 | GtkStateType state = iconStateString.EqualsLiteral("disabled") | |||
| 340 | ? GTK_STATE_INSENSITIVE | |||
| 341 | : GTK_STATE_NORMAL; | |||
| 342 | ||||
| 343 | // First lookup the icon by stock id and text direction. | |||
| 344 | GtkTextDirection direction = GTK_TEXT_DIR_NONE; | |||
| 345 | if (StringEndsWith(stockIcon, "-ltr"_ns)) { | |||
| 346 | direction = GTK_TEXT_DIR_LTR; | |||
| 347 | } else if (StringEndsWith(stockIcon, "-rtl"_ns)) { | |||
| 348 | direction = GTK_TEXT_DIR_RTL; | |||
| 349 | } | |||
| 350 | ||||
| 351 | bool forceDirection = direction != GTK_TEXT_DIR_NONE; | |||
| 352 | nsAutoCString stockID; | |||
| 353 | bool useIconName = false; | |||
| 354 | if (!forceDirection) { | |||
| 355 | direction = gtk_widget_get_default_direction(); | |||
| 356 | stockID = stockIcon; | |||
| 357 | } else { | |||
| 358 | // GTK versions < 2.22 use icon names from concatenating stock id with | |||
| 359 | // -(rtl|ltr), which is how the moz-icon stock name is interpreted here. | |||
| 360 | stockID = Substring(stockIcon, 0, stockIcon.Length() - 4); | |||
| 361 | // However, if we lookup bidi icons by the stock name, then GTK versions | |||
| 362 | // >= 2.22 will use a bidi lookup convention that most icon themes do not | |||
| 363 | // yet follow. Therefore, we first check to see if the theme supports the | |||
| 364 | // old icon name as this will have bidi support (if found). | |||
| 365 | GtkIconTheme* icon_theme = gtk_icon_theme_get_default(); | |||
| 366 | // Micking what gtk_icon_set_render_icon does with sizes, though it's not | |||
| 367 | // critical as icons will be scaled to suit size. It just means we follow | |||
| 368 | // the same paths and so share caches. | |||
| 369 | gint width, height; | |||
| 370 | if (gtk_icon_size_lookup(icon_size, &width, &height)) { | |||
| 371 | gint size = std::min(width, height); | |||
| 372 | // We use gtk_icon_theme_lookup_icon() without | |||
| 373 | // GTK_ICON_LOOKUP_USE_BUILTIN instead of gtk_icon_theme_has_icon() so | |||
| 374 | // we don't pick up fallback icons added by distributions for backward | |||
| 375 | // compatibility. | |||
| 376 | GtkIconInfo* icon = gtk_icon_theme_lookup_icon( | |||
| 377 | icon_theme, stockIcon.get(), size, (GtkIconLookupFlags)0); | |||
| 378 | if (icon) { | |||
| 379 | useIconName = true; | |||
| 380 | gtk_icon_info_free(icon); | |||
| 381 | } | |||
| 382 | } | |||
| 383 | } | |||
| 384 | ||||
| 385 | ensure_stock_image_widget(); | |||
| 386 | GtkStyle* style = gtk_widget_get_style(gStockImageWidget); | |||
| 387 | GtkIconSet* icon_set = nullptr; | |||
| 388 | if (!useIconName) { | |||
| 389 | icon_set = gtk_style_lookup_icon_set(style, stockID.get()); | |||
| 390 | } | |||
| 391 | ||||
| 392 | if (!icon_set) { | |||
| 393 | // Either we have chosen icon-name lookup for a bidi icon, or stockIcon is | |||
| 394 | // not a stock id so we assume it is an icon name. | |||
| 395 | useIconName = true; | |||
| 396 | // Creating a GtkIconSet is a convenient way to allow the style to | |||
| 397 | // render the icon, possibly with variations suitable for insensitive | |||
| 398 | // states. | |||
| 399 | icon_set = gtk_icon_set_new(); | |||
| 400 | GtkIconSource* icon_source = gtk_icon_source_new(); | |||
| 401 | ||||
| 402 | gtk_icon_source_set_icon_name(icon_source, stockIcon.get()); | |||
| 403 | gtk_icon_set_add_source(icon_set, icon_source); | |||
| 404 | gtk_icon_source_free(icon_source); | |||
| 405 | } | |||
| 406 | ||||
| 407 | GdkPixbuf* icon = gtk_icon_set_render_icon( | |||
| 408 | icon_set, style, direction, state, icon_size, gStockImageWidget, nullptr); | |||
| 409 | if (useIconName) { | |||
| 410 | gtk_icon_set_unref(icon_set); | |||
| 411 | } | |||
| 412 | ||||
| 413 | // According to documentation, gtk_icon_set_render_icon() never returns | |||
| 414 | // nullptr, but it does return nullptr when we have the problem reported | |||
| 415 | // here: https://bugzilla.gnome.org/show_bug.cgi?id=629878#c13 | |||
| 416 | if (!icon) { | |||
| 417 | return NS_ERROR_NOT_AVAILABLE; | |||
| 418 | } | |||
| 419 | ||||
| 420 | nsresult rv = MozGdkPixbufToByteBuf(icon, aDataOut); | |||
| 421 | ||||
| 422 | g_object_unref(icon); | |||
| 423 | ||||
| 424 | return rv; | |||
| 425 | } | |||
| 426 | ||||
| 427 | nsresult nsIconChannel::Init(nsIURI* aURI) { | |||
| 428 | nsCOMPtr<nsIInputStream> stream; | |||
| 429 | ||||
| 430 | using ContentChild = mozilla::dom::ContentChild; | |||
| 431 | if (auto* contentChild = ContentChild::GetSingleton()) { | |||
| 432 | // Get the icon via IPC and translate the promise of a ByteBuf | |||
| 433 | // into an actually-existing channel. | |||
| 434 | RefPtr<ContentChild::GetSystemIconPromise> icon = | |||
| 435 | contentChild->SendGetSystemIcon(aURI); | |||
| 436 | if (!icon) { | |||
| 437 | return NS_ERROR_UNEXPECTED; | |||
| 438 | } | |||
| 439 | ||||
| 440 | nsCOMPtr<nsIAsyncInputStream> inputStream; | |||
| 441 | nsCOMPtr<nsIAsyncOutputStream> outputStream; | |||
| 442 | NS_NewPipe2(getter_AddRefs(inputStream), getter_AddRefs(outputStream), true, | |||
| 443 | false, 0, UINT32_MAX(4294967295U)); | |||
| 444 | ||||
| 445 | // FIXME: Bug 1718324 | |||
| 446 | // The GetSystemIcon() call will end up on the parent doing GetIcon() | |||
| 447 | // and by using ByteBuf we might not be immune to some deadlock, at least | |||
| 448 | // on paper. From analysis in | |||
| 449 | // https://phabricator.services.mozilla.com/D118596#3865440 we should be | |||
| 450 | // safe in practice, but it would be nicer to just write that differently. | |||
| 451 | ||||
| 452 | icon->Then( | |||
| 453 | mozilla::GetCurrentSerialEventTarget(), __func__, | |||
| 454 | [outputStream](std::tuple<nsresult, mozilla::Maybe<ByteBuf>>&& aArg) { | |||
| 455 | nsresult rv = std::get<0>(aArg); | |||
| 456 | mozilla::Maybe<ByteBuf> bytes = std::move(std::get<1>(aArg)); | |||
| 457 | ||||
| 458 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { | |||
| ||||
| 459 | MOZ_RELEASE_ASSERT(bytes)do { static_assert( mozilla::detail::AssertionConditionType< decltype(bytes)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(bytes))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("bytes", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 459); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "bytes" ")"); do { *((volatile int*)__null) = 459; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 460 | uint32_t written; | |||
| 461 | rv = outputStream->Write(reinterpret_cast<char*>(bytes->mData), | |||
| 462 | static_cast<uint32_t>(bytes->mLen), | |||
| 463 | &written); | |||
| 464 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { | |||
| 465 | const bool wroteAll = static_cast<size_t>(written) == bytes->mLen; | |||
| 466 | MOZ_ASSERT(wroteAll)do { static_assert( mozilla::detail::AssertionConditionType< decltype(wroteAll)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(wroteAll))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("wroteAll", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wroteAll" ")" ); do { *((volatile int*)__null) = 466; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 467 | if (!wroteAll) { | |||
| 468 | rv = NS_ERROR_UNEXPECTED; | |||
| 469 | } | |||
| 470 | } | |||
| 471 | } else { | |||
| 472 | MOZ_ASSERT(!bytes)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!bytes)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(!bytes))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!bytes", "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 472); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!bytes" ")") ; do { *((volatile int*)__null) = 472; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 473 | } | |||
| 474 | ||||
| 475 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { | |||
| 476 | outputStream->CloseWithStatus(rv); | |||
| 477 | } | |||
| 478 | }, | |||
| 479 | [outputStream](mozilla::ipc::ResponseRejectReason) { | |||
| 480 | outputStream->CloseWithStatus(NS_ERROR_FAILURE); | |||
| 481 | }); | |||
| 482 | ||||
| 483 | stream = inputStream.forget(); | |||
| 484 | } else { | |||
| 485 | // Get the icon directly. | |||
| 486 | ByteBuf bytebuf; | |||
| 487 | nsresult rv = GetIcon(aURI, &bytebuf); | |||
| 488 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 488); return rv; } } while (false); | |||
| 489 | ||||
| 490 | rv = ByteBufToStream(std::move(bytebuf), getter_AddRefs(stream)); | |||
| 491 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/image/decoders/icon/gtk/nsIconChannel.cpp" , 491); return rv; } } while (false); | |||
| 492 | } | |||
| 493 | ||||
| 494 | return StreamToChannel(stream.forget(), aURI, getter_AddRefs(mRealChannel)); | |||
| 495 | } | |||
| 496 | ||||
| 497 | void nsIconChannel::Shutdown() { | |||
| 498 | if (gProtoWindow) { | |||
| 499 | gtk_widget_destroy(gProtoWindow); | |||
| 500 | gProtoWindow = nullptr; | |||
| 501 | gStockImageWidget = nullptr; | |||
| 502 | } | |||
| 503 | } |
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
| 5 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | #ifndef DOM_QUOTA_FORWARD_DECLS_H_ |
| 8 | #define DOM_QUOTA_FORWARD_DECLS_H_ |
| 9 | |
| 10 | #include <cstdint> |
| 11 | #include <functional> |
| 12 | |
| 13 | #include "nsStringFwd.h" |
| 14 | #include "nsTArrayForwardDeclare.h" |
| 15 | #include "mozilla/dom/quota/CommonMetadataArrayFwd.h" |
| 16 | #include "mozilla/dom/quota/Config.h" |
| 17 | |
| 18 | enum class nsresult : uint32_t; |
| 19 | template <class T> |
| 20 | class RefPtr; |
| 21 | |
| 22 | namespace mozilla { |
| 23 | |
| 24 | using CStringArray = nsTArray<nsCString>; |
| 25 | |
| 26 | template <class T> |
| 27 | class Maybe; |
| 28 | |
| 29 | using MaybeCStringArray = Maybe<CStringArray>; |
| 30 | |
| 31 | #ifdef QM_ERROR_STACKS_ENABLED |
| 32 | class QMResult; |
| 33 | #else |
| 34 | using QMResult = nsresult; |
| 35 | #endif |
| 36 | |
| 37 | struct Ok; |
| 38 | template <typename V, typename E> |
| 39 | class Result; |
| 40 | |
| 41 | using OkOrErr = Result<Ok, QMResult>; |
| 42 | |
| 43 | template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> |
| 44 | class MozPromise; |
| 45 | |
| 46 | using BoolPromise = MozPromise<bool, nsresult, false>; |
| 47 | using Int64Promise = MozPromise<int64_t, nsresult, false>; |
| 48 | using UInt64Promise = MozPromise<uint64_t, nsresult, false>; |
| 49 | using CStringArrayPromise = MozPromise<CStringArray, nsresult, true>; |
| 50 | |
| 51 | using MaybeCStringArrayPromise = MozPromise<MaybeCStringArray, nsresult, true>; |
| 52 | |
| 53 | using ExclusiveBoolPromise = MozPromise<bool, nsresult, true>; |
| 54 | |
| 55 | namespace ipc { |
| 56 | |
| 57 | class BoolResponse; |
| 58 | class UInt64Response; |
| 59 | class CStringArrayResponse; |
| 60 | enum class ResponseRejectReason; |
| 61 | |
| 62 | using BoolResponsePromise = |
| 63 | MozPromise<BoolResponse, ResponseRejectReason, true>; |
| 64 | using UInt64ResponsePromise = |
| 65 | MozPromise<UInt64Response, ResponseRejectReason, true>; |
| 66 | using CStringArrayResponsePromise = |
| 67 | MozPromise<CStringArrayResponse, ResponseRejectReason, true>; |
| 68 | |
| 69 | using NSResultResolver = std::function<void(const nsresult&)>; |
| 70 | |
| 71 | using BoolResponseResolver = std::function<void(const BoolResponse&)>; |
| 72 | using UInt64ResponseResolver = std::function<void(const UInt64Response&)>; |
| 73 | using CStringArrayResponseResolver = |
| 74 | std::function<void(const CStringArrayResponse&)>; |
| 75 | |
| 76 | } // namespace ipc |
| 77 | |
| 78 | namespace dom::quota { |
| 79 | |
| 80 | class ClientDirectoryLock; |
| 81 | class UniversalDirectoryLock; |
| 82 | |
| 83 | using ClientDirectoryLockPromise = |
| 84 | MozPromise<RefPtr<ClientDirectoryLock>, nsresult, true>; |
| 85 | using UniversalDirectoryLockPromise = |
| 86 | MozPromise<RefPtr<UniversalDirectoryLock>, nsresult, true>; |
| 87 | |
| 88 | struct OriginMetadata; |
| 89 | struct PrincipalMetadata; |
| 90 | using OriginMetadataArray = nsTArray<OriginMetadata>; |
| 91 | using PrincipalMetadataArray = nsTArray<PrincipalMetadata>; |
| 92 | using MaybePrincipalMetadataArray = Maybe<PrincipalMetadataArray>; |
| 93 | class UsageInfo; |
| 94 | |
| 95 | using OriginMetadataArrayPromise = |
| 96 | MozPromise<OriginMetadataArray, nsresult, true>; |
| 97 | using OriginUsageMetadataArrayPromise = |
| 98 | MozPromise<OriginUsageMetadataArray, nsresult, true>; |
| 99 | using MaybePrincipalMetadataArrayPromise = |
| 100 | MozPromise<MaybePrincipalMetadataArray, nsresult, true>; |
| 101 | using UsageInfoPromise = MozPromise<UsageInfo, nsresult, false>; |
| 102 | |
| 103 | class OriginUsageMetadataArrayResponse; |
| 104 | class UsageInfoResponse; |
| 105 | |
| 106 | using OriginUsageMetadataArrayResponsePromise = |
| 107 | MozPromise<OriginUsageMetadataArrayResponse, |
| 108 | mozilla::ipc::ResponseRejectReason, true>; |
| 109 | using UsageInfoResponsePromise = |
| 110 | MozPromise<UsageInfoResponse, mozilla::ipc::ResponseRejectReason, true>; |
| 111 | |
| 112 | using OriginUsageMetadataArrayResponseResolver = |
| 113 | std::function<void(OriginUsageMetadataArrayResponse&&)>; |
| 114 | using UsageInfoResponseResolver = std::function<void(const UsageInfoResponse&)>; |
| 115 | |
| 116 | } // namespace dom::quota |
| 117 | |
| 118 | } // namespace mozilla |
| 119 | |
| 120 | #endif // DOM_QUOTA_FORWARD_DECLS_H_ |
| 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||||||||||
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ | ||||||||||
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public | ||||||||||
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||||||
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||||||||
| 6 | |||||||||||
| 7 | /* A class for optional values and in-place lazy construction. */ | ||||||||||
| 8 | |||||||||||
| 9 | #ifndef mozilla_Maybe_h | ||||||||||
| 10 | #define mozilla_Maybe_h | ||||||||||
| 11 | |||||||||||
| 12 | #include <functional> | ||||||||||
| 13 | #include <new> // for placement new | ||||||||||
| 14 | #include <ostream> | ||||||||||
| 15 | #include <type_traits> | ||||||||||
| 16 | #include <utility> | ||||||||||
| 17 | |||||||||||
| 18 | #include "mozilla/Alignment.h" | ||||||||||
| 19 | #include "mozilla/Assertions.h" | ||||||||||
| 20 | #include "mozilla/Attributes.h" | ||||||||||
| 21 | #include "mozilla/MaybeStorageBase.h" | ||||||||||
| 22 | #include "mozilla/MemoryChecking.h" | ||||||||||
| 23 | #include "mozilla/OperatorNewExtensions.h" | ||||||||||
| 24 | #include "mozilla/Poison.h" | ||||||||||
| 25 | #include "mozilla/ThreadSafety.h" | ||||||||||
| 26 | |||||||||||
| 27 | class nsCycleCollectionTraversalCallback; | ||||||||||
| 28 | |||||||||||
| 29 | template <typename T> | ||||||||||
| 30 | inline void CycleCollectionNoteChild( | ||||||||||
| 31 | nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName, | ||||||||||
| 32 | uint32_t aFlags); | ||||||||||
| 33 | |||||||||||
| 34 | namespace mozilla { | ||||||||||
| 35 | |||||||||||
| 36 | struct Nothing {}; | ||||||||||
| 37 | |||||||||||
| 38 | inline constexpr bool operator==(const Nothing&, const Nothing&) { | ||||||||||
| 39 | return true; | ||||||||||
| 40 | } | ||||||||||
| 41 | |||||||||||
| 42 | template <class T> | ||||||||||
| 43 | class Maybe; | ||||||||||
| 44 | |||||||||||
| 45 | namespace detail { | ||||||||||
| 46 | |||||||||||
| 47 | // You would think that poisoning Maybe instances could just be a call | ||||||||||
| 48 | // to mozWritePoison. Unfortunately, using a simple call to | ||||||||||
| 49 | // mozWritePoison generates poor code on MSVC for small structures. The | ||||||||||
| 50 | // generated code contains (always not-taken) branches and does a bunch | ||||||||||
| 51 | // of setup for `rep stos{l,q}`, even though we know at compile time | ||||||||||
| 52 | // exactly how many words we're poisoning. Instead, we're going to | ||||||||||
| 53 | // force MSVC to generate the code we want via recursive templates. | ||||||||||
| 54 | |||||||||||
| 55 | // Write the given poisonValue into p at offset*sizeof(uintptr_t). | ||||||||||
| 56 | template <size_t offset> | ||||||||||
| 57 | inline void WritePoisonAtOffset(void* p, const uintptr_t poisonValue) { | ||||||||||
| 58 | memcpy(static_cast<char*>(p) + offset * sizeof(poisonValue), &poisonValue, | ||||||||||
| 59 | sizeof(poisonValue)); | ||||||||||
| 60 | } | ||||||||||
| 61 | |||||||||||
| 62 | template <size_t Offset, size_t NOffsets> | ||||||||||
| 63 | struct InlinePoisoner { | ||||||||||
| 64 | static void poison(void* p, const uintptr_t poisonValue) { | ||||||||||
| 65 | WritePoisonAtOffset<Offset>(p, poisonValue); | ||||||||||
| 66 | InlinePoisoner<Offset + 1, NOffsets>::poison(p, poisonValue); | ||||||||||
| 67 | } | ||||||||||
| 68 | }; | ||||||||||
| 69 | |||||||||||
| 70 | template <size_t N> | ||||||||||
| 71 | struct InlinePoisoner<N, N> { | ||||||||||
| 72 | static void poison(void*, const uintptr_t) { | ||||||||||
| 73 | // All done! | ||||||||||
| 74 | } | ||||||||||
| 75 | }; | ||||||||||
| 76 | |||||||||||
| 77 | // We can't generate inline code for large structures, though, because we'll | ||||||||||
| 78 | // blow out recursive template instantiation limits, and the code would be | ||||||||||
| 79 | // bloated to boot. So provide a fallback to the out-of-line poisoner. | ||||||||||
| 80 | template <size_t ObjectSize> | ||||||||||
| 81 | struct OutOfLinePoisoner { | ||||||||||
| 82 | static MOZ_NEVER_INLINE__attribute__((noinline)) void poison(void* p, const uintptr_t) { | ||||||||||
| 83 | mozWritePoison(p, ObjectSize); | ||||||||||
| 84 | } | ||||||||||
| 85 | }; | ||||||||||
| 86 | |||||||||||
| 87 | template <typename T> | ||||||||||
| 88 | inline void PoisonObject(T* p) { | ||||||||||
| 89 | const uintptr_t POISON = mozPoisonValue(); | ||||||||||
| 90 | std::conditional_t<(sizeof(T) <= 8 * sizeof(POISON)), | ||||||||||
| 91 | InlinePoisoner<0, sizeof(T) / sizeof(POISON)>, | ||||||||||
| 92 | OutOfLinePoisoner<sizeof(T)>>::poison(p, POISON); | ||||||||||
| 93 | } | ||||||||||
| 94 | |||||||||||
| 95 | template <typename T> | ||||||||||
| 96 | struct MaybePoisoner { | ||||||||||
| 97 | static const size_t N = sizeof(T); | ||||||||||
| 98 | |||||||||||
| 99 | static void poison(void* aPtr) { | ||||||||||
| 100 | #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1 | ||||||||||
| 101 | if (N >= sizeof(uintptr_t)) { | ||||||||||
| 102 | PoisonObject(static_cast<std::remove_cv_t<T>*>(aPtr)); | ||||||||||
| 103 | } | ||||||||||
| 104 | #endif | ||||||||||
| 105 | MOZ_MAKE_MEM_UNDEFINED(aPtr, N)do { } while (0); | ||||||||||
| 106 | } | ||||||||||
| 107 | }; | ||||||||||
| 108 | |||||||||||
| 109 | template <typename T, | ||||||||||
| 110 | bool TriviallyDestructibleAndCopyable = | ||||||||||
| 111 | IsTriviallyDestructibleAndCopyable<T>, | ||||||||||
| 112 | bool Copyable = std::is_copy_constructible_v<T>, | ||||||||||
| 113 | bool Movable = std::is_move_constructible_v<T>> | ||||||||||
| 114 | class Maybe_CopyMove_Enabler; | ||||||||||
| 115 | |||||||||||
| 116 | #define MOZ_MAYBE_COPY_OPS() \ | ||||||||||
| 117 | Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler& aOther) { \ | ||||||||||
| 118 | if (downcast(aOther).isSome()) { \ | ||||||||||
| 119 | downcast(*this).emplace(*downcast(aOther)); \ | ||||||||||
| 120 | } \ | ||||||||||
| 121 | } \ | ||||||||||
| 122 | \ | ||||||||||
| 123 | Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler& aOther) { \ | ||||||||||
| 124 | return downcast(*this).template operator= <T>(downcast(aOther)); \ | ||||||||||
| 125 | } | ||||||||||
| 126 | |||||||||||
| 127 | #define MOZ_MAYBE_MOVE_OPS() \ | ||||||||||
| 128 | constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { \ | ||||||||||
| 129 | if (downcast(aOther).isSome()) { \ | ||||||||||
| 130 | downcast(*this).emplace(std::move(*downcast(aOther))); \ | ||||||||||
| 131 | downcast(aOther).reset(); \ | ||||||||||
| 132 | } \ | ||||||||||
| 133 | } \ | ||||||||||
| 134 | \ | ||||||||||
| 135 | constexpr Maybe_CopyMove_Enabler& operator=( \ | ||||||||||
| 136 | Maybe_CopyMove_Enabler&& aOther) { \ | ||||||||||
| 137 | downcast(*this).template operator= <T>(std::move(downcast(aOther))); \ | ||||||||||
| 138 | \ | ||||||||||
| 139 | return *this; \ | ||||||||||
| 140 | } | ||||||||||
| 141 | |||||||||||
| 142 | #define MOZ_MAYBE_DOWNCAST() \ | ||||||||||
| 143 | static constexpr Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \ | ||||||||||
| 144 | return static_cast<Maybe<T>&>(aObj); \ | ||||||||||
| 145 | } \ | ||||||||||
| 146 | static constexpr const Maybe<T>& downcast( \ | ||||||||||
| 147 | const Maybe_CopyMove_Enabler& aObj) { \ | ||||||||||
| 148 | return static_cast<const Maybe<T>&>(aObj); \ | ||||||||||
| 149 | } | ||||||||||
| 150 | |||||||||||
| 151 | template <typename T> | ||||||||||
| 152 | class Maybe_CopyMove_Enabler<T, true, true, true> { | ||||||||||
| 153 | public: | ||||||||||
| 154 | Maybe_CopyMove_Enabler() = default; | ||||||||||
| 155 | |||||||||||
| 156 | Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = default; | ||||||||||
| 157 | Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = default; | ||||||||||
| 158 | constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { | ||||||||||
| 159 | downcast(aOther).reset(); | ||||||||||
| 160 | } | ||||||||||
| 161 | constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) { | ||||||||||
| 162 | downcast(aOther).reset(); | ||||||||||
| 163 | return *this; | ||||||||||
| 164 | } | ||||||||||
| 165 | |||||||||||
| 166 | private: | ||||||||||
| 167 | MOZ_MAYBE_DOWNCAST() | ||||||||||
| 168 | }; | ||||||||||
| 169 | |||||||||||
| 170 | template <typename T> | ||||||||||
| 171 | class Maybe_CopyMove_Enabler<T, true, false, true> { | ||||||||||
| 172 | public: | ||||||||||
| 173 | Maybe_CopyMove_Enabler() = default; | ||||||||||
| 174 | |||||||||||
| 175 | Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete; | ||||||||||
| 176 | Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete; | ||||||||||
| 177 | constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { | ||||||||||
| 178 | downcast(aOther).reset(); | ||||||||||
| 179 | } | ||||||||||
| 180 | constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) { | ||||||||||
| 181 | downcast(aOther).reset(); | ||||||||||
| 182 | return *this; | ||||||||||
| 183 | } | ||||||||||
| 184 | |||||||||||
| 185 | private: | ||||||||||
| 186 | MOZ_MAYBE_DOWNCAST() | ||||||||||
| 187 | }; | ||||||||||
| 188 | |||||||||||
| 189 | template <typename T> | ||||||||||
| 190 | class Maybe_CopyMove_Enabler<T, false, true, true> { | ||||||||||
| 191 | public: | ||||||||||
| 192 | Maybe_CopyMove_Enabler() = default; | ||||||||||
| 193 | |||||||||||
| 194 | MOZ_MAYBE_COPY_OPS() | ||||||||||
| 195 | MOZ_MAYBE_MOVE_OPS() | ||||||||||
| 196 | |||||||||||
| 197 | private: | ||||||||||
| 198 | MOZ_MAYBE_DOWNCAST() | ||||||||||
| 199 | }; | ||||||||||
| 200 | |||||||||||
| 201 | template <typename T> | ||||||||||
| 202 | class Maybe_CopyMove_Enabler<T, false, false, true> { | ||||||||||
| 203 | public: | ||||||||||
| 204 | Maybe_CopyMove_Enabler() = default; | ||||||||||
| 205 | |||||||||||
| 206 | Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete; | ||||||||||
| 207 | Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete; | ||||||||||
| 208 | MOZ_MAYBE_MOVE_OPS() | ||||||||||
| 209 | |||||||||||
| 210 | private: | ||||||||||
| 211 | MOZ_MAYBE_DOWNCAST() | ||||||||||
| 212 | }; | ||||||||||
| 213 | |||||||||||
| 214 | template <typename T> | ||||||||||
| 215 | class Maybe_CopyMove_Enabler<T, false, true, false> { | ||||||||||
| 216 | public: | ||||||||||
| 217 | Maybe_CopyMove_Enabler() = default; | ||||||||||
| 218 | |||||||||||
| 219 | MOZ_MAYBE_COPY_OPS() | ||||||||||
| 220 | Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete; | ||||||||||
| 221 | Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete; | ||||||||||
| 222 | |||||||||||
| 223 | private: | ||||||||||
| 224 | MOZ_MAYBE_DOWNCAST() | ||||||||||
| 225 | }; | ||||||||||
| 226 | |||||||||||
| 227 | template <typename T, bool TriviallyDestructibleAndCopyable> | ||||||||||
| 228 | class Maybe_CopyMove_Enabler<T, TriviallyDestructibleAndCopyable, false, | ||||||||||
| 229 | false> { | ||||||||||
| 230 | public: | ||||||||||
| 231 | Maybe_CopyMove_Enabler() = default; | ||||||||||
| 232 | |||||||||||
| 233 | Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete; | ||||||||||
| 234 | Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete; | ||||||||||
| 235 | Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete; | ||||||||||
| 236 | Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete; | ||||||||||
| 237 | }; | ||||||||||
| 238 | |||||||||||
| 239 | #undef MOZ_MAYBE_COPY_OPS | ||||||||||
| 240 | #undef MOZ_MAYBE_MOVE_OPS | ||||||||||
| 241 | #undef MOZ_MAYBE_DOWNCAST | ||||||||||
| 242 | |||||||||||
| 243 | template <typename T, bool TriviallyDestructibleAndCopyable = | ||||||||||
| 244 | IsTriviallyDestructibleAndCopyable<T>> | ||||||||||
| 245 | struct MaybeStorage; | ||||||||||
| 246 | |||||||||||
| 247 | template <typename T> | ||||||||||
| 248 | struct MaybeStorage<T, false> : MaybeStorageBase<T> { | ||||||||||
| 249 | protected: | ||||||||||
| 250 | char mIsSome = false; // not bool -- guarantees minimal space consumption | ||||||||||
| 251 | |||||||||||
| 252 | constexpr MaybeStorage() = default; | ||||||||||
| 253 | explicit MaybeStorage(const T& aVal) | ||||||||||
| 254 | : MaybeStorageBase<T>{aVal}, mIsSome{true} {} | ||||||||||
| 255 | explicit MaybeStorage(T&& aVal) | ||||||||||
| 256 | : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {} | ||||||||||
| 257 | |||||||||||
| 258 | template <typename... Args> | ||||||||||
| 259 | explicit MaybeStorage(std::in_place_t, Args&&... aArgs) | ||||||||||
| 260 | : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...}, | ||||||||||
| 261 | mIsSome{true} {} | ||||||||||
| 262 | |||||||||||
| 263 | public: | ||||||||||
| 264 | // Copy and move operations are no-ops, since copying is moving is implemented | ||||||||||
| 265 | // by Maybe_CopyMove_Enabler. | ||||||||||
| 266 | |||||||||||
| 267 | MaybeStorage(const MaybeStorage&) : MaybeStorageBase<T>{} {} | ||||||||||
| 268 | MaybeStorage& operator=(const MaybeStorage&) { return *this; } | ||||||||||
| 269 | MaybeStorage(MaybeStorage&&) : MaybeStorageBase<T>{} {} | ||||||||||
| 270 | MaybeStorage& operator=(MaybeStorage&&) { return *this; } | ||||||||||
| 271 | |||||||||||
| 272 | ~MaybeStorage() { | ||||||||||
| 273 | if (mIsSome
| ||||||||||
| 274 | this->addr()->T::~T(); | ||||||||||
| 275 | } | ||||||||||
| 276 | } | ||||||||||
| 277 | }; | ||||||||||
| 278 | |||||||||||
| 279 | template <typename T> | ||||||||||
| 280 | struct MaybeStorage<T, true> : MaybeStorageBase<T> { | ||||||||||
| 281 | protected: | ||||||||||
| 282 | char mIsSome = false; // not bool -- guarantees minimal space consumption | ||||||||||
| 283 | |||||||||||
| 284 | constexpr MaybeStorage() = default; | ||||||||||
| 285 | constexpr explicit MaybeStorage(const T& aVal) | ||||||||||
| 286 | : MaybeStorageBase<T>{aVal}, mIsSome{true} {} | ||||||||||
| 287 | constexpr explicit MaybeStorage(T&& aVal) | ||||||||||
| 288 | : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {} | ||||||||||
| 289 | |||||||||||
| 290 | template <typename... Args> | ||||||||||
| 291 | constexpr explicit MaybeStorage(std::in_place_t, Args&&... aArgs) | ||||||||||
| 292 | : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...}, | ||||||||||
| 293 | mIsSome{true} {} | ||||||||||
| 294 | }; | ||||||||||
| 295 | |||||||||||
| 296 | template <typename T> | ||||||||||
| 297 | struct IsMaybeImpl : std::false_type {}; | ||||||||||
| 298 | |||||||||||
| 299 | template <typename T> | ||||||||||
| 300 | struct IsMaybeImpl<Maybe<T>> : std::true_type {}; | ||||||||||
| 301 | |||||||||||
| 302 | template <typename T> | ||||||||||
| 303 | using IsMaybe = IsMaybeImpl<std::decay_t<T>>; | ||||||||||
| 304 | |||||||||||
| 305 | } // namespace detail | ||||||||||
| 306 | |||||||||||
| 307 | template <typename T, typename U = typename std::remove_cv< | ||||||||||
| 308 | typename std::remove_reference<T>::type>::type> | ||||||||||
| 309 | constexpr Maybe<U> Some(T&& aValue); | ||||||||||
| 310 | |||||||||||
| 311 | /* | ||||||||||
| 312 | * Maybe is a container class which contains either zero or one elements. It | ||||||||||
| 313 | * serves two roles. It can represent values which are *semantically* optional, | ||||||||||
| 314 | * augmenting a type with an explicit 'Nothing' value. In this role, it provides | ||||||||||
| 315 | * methods that make it easy to work with values that may be missing, along with | ||||||||||
| 316 | * equality and comparison operators so that Maybe values can be stored in | ||||||||||
| 317 | * containers. Maybe values can be constructed conveniently in expressions using | ||||||||||
| 318 | * type inference, as follows: | ||||||||||
| 319 | * | ||||||||||
| 320 | * void doSomething(Maybe<Foo> aFoo) { | ||||||||||
| 321 | * if (aFoo) // Make sure that aFoo contains a value... | ||||||||||
| 322 | * aFoo->takeAction(); // and then use |aFoo->| to access it. | ||||||||||
| 323 | * } // |*aFoo| also works! | ||||||||||
| 324 | * | ||||||||||
| 325 | * doSomething(Nothing()); // Passes a Maybe<Foo> containing no value. | ||||||||||
| 326 | * doSomething(Some(Foo(100))); // Passes a Maybe<Foo> containing |Foo(100)|. | ||||||||||
| 327 | * | ||||||||||
| 328 | * You'll note that it's important to check whether a Maybe contains a value | ||||||||||
| 329 | * before using it, using conversion to bool, |isSome()|, or |isNothing()|. You | ||||||||||
| 330 | * can avoid these checks, and sometimes write more readable code, using | ||||||||||
| 331 | * |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value | ||||||||||
| 332 | * in the Maybe and provide a default for the 'Nothing' case. You can also use | ||||||||||
| 333 | * |apply()| to call a function only if the Maybe holds a value, and |map()| to | ||||||||||
| 334 | * transform the value in the Maybe, returning another Maybe with a possibly | ||||||||||
| 335 | * different type. | ||||||||||
| 336 | * | ||||||||||
| 337 | * Maybe's other role is to support lazily constructing objects without using | ||||||||||
| 338 | * dynamic storage. A Maybe directly contains storage for a value, but it's | ||||||||||
| 339 | * empty by default. |emplace()|, as mentioned above, can be used to construct a | ||||||||||
| 340 | * value in Maybe's storage. The value a Maybe contains can be destroyed by | ||||||||||
| 341 | * calling |reset()|; this will happen automatically if a Maybe is destroyed | ||||||||||
| 342 | * while holding a value. | ||||||||||
| 343 | * | ||||||||||
| 344 | * It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null | ||||||||||
| 345 | * value meaning 'Nothing' and any other value meaning 'Some'. You can convert | ||||||||||
| 346 | * from such a pointer to a Maybe value using 'ToMaybe()'. | ||||||||||
| 347 | * | ||||||||||
| 348 | * Maybe is inspired by similar types in the standard library of many other | ||||||||||
| 349 | * languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's | ||||||||||
| 350 | * very similar to std::optional, which was proposed for C++14 and originated in | ||||||||||
| 351 | * Boost. The most important differences between Maybe and std::optional are: | ||||||||||
| 352 | * | ||||||||||
| 353 | * - std::optional<T> may be compared with T. We deliberately forbid that. | ||||||||||
| 354 | * - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but | ||||||||||
| 355 | * lacks corresponding methods for |refOr()| and |ptrOr()|. | ||||||||||
| 356 | * - std::optional lacks |map()| and |apply()|, making it less suitable for | ||||||||||
| 357 | * functional-style code. | ||||||||||
| 358 | * - std::optional lacks many convenience functions that Maybe has. Most | ||||||||||
| 359 | * unfortunately, it lacks equivalents of the type-inferred constructor | ||||||||||
| 360 | * functions |Some()| and |Nothing()|. | ||||||||||
| 361 | */ | ||||||||||
| 362 | template <class T> | ||||||||||
| 363 | class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe | ||||||||||
| 364 | : private detail::MaybeStorage<T>, | ||||||||||
| 365 | public detail::Maybe_CopyMove_Enabler<T> { | ||||||||||
| 366 | template <typename, bool, bool, bool> | ||||||||||
| 367 | friend class detail::Maybe_CopyMove_Enabler; | ||||||||||
| 368 | |||||||||||
| 369 | template <typename U, typename V> | ||||||||||
| 370 | friend constexpr Maybe<V> Some(U&& aValue); | ||||||||||
| 371 | |||||||||||
| 372 | struct SomeGuard {}; | ||||||||||
| 373 | |||||||||||
| 374 | template <typename U> | ||||||||||
| 375 | constexpr Maybe(U&& aValue, SomeGuard) | ||||||||||
| 376 | : detail::MaybeStorage<T>{std::forward<U>(aValue)} {} | ||||||||||
| 377 | |||||||||||
| 378 | using detail::MaybeStorage<T>::mIsSome; | ||||||||||
| 379 | using detail::MaybeStorage<T>::mStorage; | ||||||||||
| 380 | |||||||||||
| 381 | void poisonData() { detail::MaybePoisoner<T>::poison(&mStorage.val); } | ||||||||||
| 382 | |||||||||||
| 383 | public: | ||||||||||
| 384 | using ValueType = T; | ||||||||||
| 385 | |||||||||||
| 386 | MOZ_ALLOW_TEMPORARY constexpr Maybe() = default; | ||||||||||
| 387 | |||||||||||
| 388 | MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {} | ||||||||||
| 389 | |||||||||||
| 390 | template <typename... Args> | ||||||||||
| 391 | constexpr explicit Maybe(std::in_place_t, Args&&... aArgs) | ||||||||||
| 392 | : detail::MaybeStorage<T>{std::in_place, std::forward<Args>(aArgs)...} {} | ||||||||||
| 393 | |||||||||||
| 394 | /** | ||||||||||
| 395 | * Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from | ||||||||||
| 396 | * a const U&. | ||||||||||
| 397 | */ | ||||||||||
| 398 | template <typename U, | ||||||||||
| 399 | std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true> | ||||||||||
| 400 | MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) { | ||||||||||
| 401 | if (aOther.isSome()) { | ||||||||||
| 402 | emplace(*aOther); | ||||||||||
| 403 | } | ||||||||||
| 404 | } | ||||||||||
| 405 | |||||||||||
| 406 | template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>, | ||||||||||
| 407 | bool> = true> | ||||||||||
| 408 | explicit Maybe(const Maybe<U>& aOther) = delete; | ||||||||||
| 409 | |||||||||||
| 410 | /** | ||||||||||
| 411 | * Maybe<T> can be move-constructed from a Maybe<U> if T is constructible from | ||||||||||
| 412 | * a U&&. | ||||||||||
| 413 | */ | ||||||||||
| 414 | template <typename U, | ||||||||||
| 415 | std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true> | ||||||||||
| 416 | MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) { | ||||||||||
| 417 | if (aOther.isSome()) { | ||||||||||
| 418 | emplace(std::move(*aOther)); | ||||||||||
| 419 | aOther.reset(); | ||||||||||
| 420 | } | ||||||||||
| 421 | } | ||||||||||
| 422 | template <typename U, | ||||||||||
| 423 | std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true> | ||||||||||
| 424 | explicit Maybe(Maybe<U>&& aOther) = delete; | ||||||||||
| 425 | |||||||||||
| 426 | template <typename U, | ||||||||||
| 427 | std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true> | ||||||||||
| 428 | Maybe& operator=(const Maybe<U>& aOther) { | ||||||||||
| 429 | if (aOther.isSome()) { | ||||||||||
| 430 | if (mIsSome) { | ||||||||||
| 431 | ref() = aOther.ref(); | ||||||||||
| 432 | } else { | ||||||||||
| 433 | emplace(*aOther); | ||||||||||
| 434 | } | ||||||||||
| 435 | } else { | ||||||||||
| 436 | reset(); | ||||||||||
| 437 | } | ||||||||||
| 438 | return *this; | ||||||||||
| 439 | } | ||||||||||
| 440 | |||||||||||
| 441 | template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>, | ||||||||||
| 442 | bool> = true> | ||||||||||
| 443 | Maybe& operator=(const Maybe<U>& aOther) = delete; | ||||||||||
| 444 | |||||||||||
| 445 | template <typename U, | ||||||||||
| 446 | std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true> | ||||||||||
| 447 | Maybe& operator=(Maybe<U>&& aOther) { | ||||||||||
| 448 | if (aOther.isSome()) { | ||||||||||
| 449 | if (mIsSome) { | ||||||||||
| 450 | ref() = std::move(aOther.ref()); | ||||||||||
| 451 | } else { | ||||||||||
| 452 | emplace(std::move(*aOther)); | ||||||||||
| 453 | } | ||||||||||
| 454 | aOther.reset(); | ||||||||||
| 455 | } else { | ||||||||||
| 456 | reset(); | ||||||||||
| 457 | } | ||||||||||
| 458 | |||||||||||
| 459 | return *this; | ||||||||||
| 460 | } | ||||||||||
| 461 | |||||||||||
| 462 | template <typename U, | ||||||||||
| 463 | std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true> | ||||||||||
| 464 | Maybe& operator=(Maybe<U>&& aOther) = delete; | ||||||||||
| 465 | |||||||||||
| 466 | constexpr Maybe& operator=(Nothing) { | ||||||||||
| 467 | reset(); | ||||||||||
| 468 | return *this; | ||||||||||
| 469 | } | ||||||||||
| 470 | |||||||||||
| 471 | /* Methods that check whether this Maybe contains a value */ | ||||||||||
| 472 | constexpr explicit operator bool() const { return isSome(); } | ||||||||||
| 473 | constexpr bool isSome() const { return mIsSome; } | ||||||||||
| 474 | constexpr bool isNothing() const { return !mIsSome; } | ||||||||||
| 475 | |||||||||||
| 476 | /* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|. | ||||||||||
| 477 | */ | ||||||||||
| 478 | constexpr T value() const&; | ||||||||||
| 479 | constexpr T value() &&; | ||||||||||
| 480 | constexpr T value() const&&; | ||||||||||
| 481 | |||||||||||
| 482 | /** | ||||||||||
| 483 | * Move the contents of this Maybe<T> out of internal storage and return it | ||||||||||
| 484 | * without calling the destructor. The internal storage is also reset to | ||||||||||
| 485 | * avoid multiple calls. Unsafe unless |isSome()|. | ||||||||||
| 486 | */ | ||||||||||
| 487 | constexpr T extract() { | ||||||||||
| 488 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 488); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 488; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 489 | T v = std::move(mStorage.val); | ||||||||||
| 490 | reset(); | ||||||||||
| 491 | return v; | ||||||||||
| 492 | } | ||||||||||
| 493 | |||||||||||
| 494 | /** | ||||||||||
| 495 | * Returns the value (possibly |Nothing()|) by moving it out of this Maybe<T> | ||||||||||
| 496 | * and leaving |Nothing()| in its place. | ||||||||||
| 497 | */ | ||||||||||
| 498 | Maybe<T> take() { return std::exchange(*this, Nothing()); } | ||||||||||
| 499 | |||||||||||
| 500 | /* | ||||||||||
| 501 | * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns | ||||||||||
| 502 | * the default value provided. | ||||||||||
| 503 | * | ||||||||||
| 504 | * Note: If the value passed to aDefault is not the result of a trivial | ||||||||||
| 505 | * expression, but expensive to evaluate, e.g. |valueOr(ExpensiveFunction())|, | ||||||||||
| 506 | * use |valueOrFrom| instead, e.g. | ||||||||||
| 507 | * |valueOrFrom([arg] { return ExpensiveFunction(arg); })|. This ensures | ||||||||||
| 508 | * that the expensive expression is only evaluated when its result will | ||||||||||
| 509 | * actually be used. | ||||||||||
| 510 | */ | ||||||||||
| 511 | template <typename V> | ||||||||||
| 512 | constexpr T valueOr(V&& aDefault) const { | ||||||||||
| 513 | if (isSome()) { | ||||||||||
| 514 | return ref(); | ||||||||||
| 515 | } | ||||||||||
| 516 | return std::forward<V>(aDefault); | ||||||||||
| 517 | } | ||||||||||
| 518 | |||||||||||
| 519 | /* | ||||||||||
| 520 | * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns | ||||||||||
| 521 | * the value returned from the function or functor provided. | ||||||||||
| 522 | */ | ||||||||||
| 523 | template <typename F> | ||||||||||
| 524 | constexpr T valueOrFrom(F&& aFunc) const { | ||||||||||
| 525 | if (isSome()) { | ||||||||||
| 526 | return ref(); | ||||||||||
| 527 | } | ||||||||||
| 528 | return aFunc(); | ||||||||||
| 529 | } | ||||||||||
| 530 | |||||||||||
| 531 | /* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|. | ||||||||||
| 532 | */ | ||||||||||
| 533 | T* ptr(); | ||||||||||
| 534 | constexpr const T* ptr() const; | ||||||||||
| 535 | |||||||||||
| 536 | /* | ||||||||||
| 537 | * Returns the contents of this Maybe<T> by pointer. If |isNothing()|, | ||||||||||
| 538 | * returns the default value provided. | ||||||||||
| 539 | */ | ||||||||||
| 540 | T* ptrOr(T* aDefault) { | ||||||||||
| 541 | if (isSome()) { | ||||||||||
| 542 | return ptr(); | ||||||||||
| 543 | } | ||||||||||
| 544 | return aDefault; | ||||||||||
| 545 | } | ||||||||||
| 546 | |||||||||||
| 547 | constexpr const T* ptrOr(const T* aDefault) const { | ||||||||||
| 548 | if (isSome()) { | ||||||||||
| 549 | return ptr(); | ||||||||||
| 550 | } | ||||||||||
| 551 | return aDefault; | ||||||||||
| 552 | } | ||||||||||
| 553 | |||||||||||
| 554 | /* | ||||||||||
| 555 | * Returns the contents of this Maybe<T> by pointer. If |isNothing()|, | ||||||||||
| 556 | * returns the value returned from the function or functor provided. | ||||||||||
| 557 | */ | ||||||||||
| 558 | template <typename F> | ||||||||||
| 559 | T* ptrOrFrom(F&& aFunc) { | ||||||||||
| 560 | if (isSome()) { | ||||||||||
| 561 | return ptr(); | ||||||||||
| 562 | } | ||||||||||
| 563 | return aFunc(); | ||||||||||
| 564 | } | ||||||||||
| 565 | |||||||||||
| 566 | template <typename F> | ||||||||||
| 567 | const T* ptrOrFrom(F&& aFunc) const { | ||||||||||
| 568 | if (isSome()) { | ||||||||||
| 569 | return ptr(); | ||||||||||
| 570 | } | ||||||||||
| 571 | return aFunc(); | ||||||||||
| 572 | } | ||||||||||
| 573 | |||||||||||
| 574 | constexpr T* operator->(); | ||||||||||
| 575 | constexpr const T* operator->() const; | ||||||||||
| 576 | |||||||||||
| 577 | /* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */ | ||||||||||
| 578 | constexpr T& ref() &; | ||||||||||
| 579 | constexpr const T& ref() const&; | ||||||||||
| 580 | constexpr T&& ref() &&; | ||||||||||
| 581 | constexpr const T&& ref() const&&; | ||||||||||
| 582 | |||||||||||
| 583 | /* | ||||||||||
| 584 | * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns | ||||||||||
| 585 | * the default value provided. | ||||||||||
| 586 | */ | ||||||||||
| 587 | constexpr T& refOr(T& aDefault) { | ||||||||||
| 588 | if (isSome()) { | ||||||||||
| 589 | return ref(); | ||||||||||
| 590 | } | ||||||||||
| 591 | return aDefault; | ||||||||||
| 592 | } | ||||||||||
| 593 | |||||||||||
| 594 | constexpr const T& refOr(const T& aDefault) const { | ||||||||||
| 595 | if (isSome()) { | ||||||||||
| 596 | return ref(); | ||||||||||
| 597 | } | ||||||||||
| 598 | return aDefault; | ||||||||||
| 599 | } | ||||||||||
| 600 | |||||||||||
| 601 | /* | ||||||||||
| 602 | * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns the | ||||||||||
| 603 | * value returned from the function or functor provided. | ||||||||||
| 604 | */ | ||||||||||
| 605 | template <typename F> | ||||||||||
| 606 | constexpr T& refOrFrom(F&& aFunc) { | ||||||||||
| 607 | if (isSome()) { | ||||||||||
| 608 | return ref(); | ||||||||||
| 609 | } | ||||||||||
| 610 | return aFunc(); | ||||||||||
| 611 | } | ||||||||||
| 612 | |||||||||||
| 613 | template <typename F> | ||||||||||
| 614 | constexpr const T& refOrFrom(F&& aFunc) const { | ||||||||||
| 615 | if (isSome()) { | ||||||||||
| 616 | return ref(); | ||||||||||
| 617 | } | ||||||||||
| 618 | return aFunc(); | ||||||||||
| 619 | } | ||||||||||
| 620 | |||||||||||
| 621 | constexpr T& operator*() &; | ||||||||||
| 622 | constexpr const T& operator*() const&; | ||||||||||
| 623 | constexpr T&& operator*() &&; | ||||||||||
| 624 | constexpr const T&& operator*() const&&; | ||||||||||
| 625 | |||||||||||
| 626 | /* If |isSome()|, runs the provided function or functor on the contents of | ||||||||||
| 627 | * this Maybe. */ | ||||||||||
| 628 | template <typename Func> | ||||||||||
| 629 | constexpr Maybe& apply(Func&& aFunc) & { | ||||||||||
| 630 | if (isSome()) { | ||||||||||
| 631 | std::forward<Func>(aFunc)(ref()); | ||||||||||
| 632 | } | ||||||||||
| 633 | return *this; | ||||||||||
| 634 | } | ||||||||||
| 635 | |||||||||||
| 636 | template <typename Func> | ||||||||||
| 637 | constexpr const Maybe& apply(Func&& aFunc) const& { | ||||||||||
| 638 | if (isSome()) { | ||||||||||
| 639 | std::forward<Func>(aFunc)(ref()); | ||||||||||
| 640 | } | ||||||||||
| 641 | return *this; | ||||||||||
| 642 | } | ||||||||||
| 643 | |||||||||||
| 644 | template <typename Func> | ||||||||||
| 645 | constexpr Maybe& apply(Func&& aFunc) && { | ||||||||||
| 646 | if (isSome()) { | ||||||||||
| 647 | std::forward<Func>(aFunc)(extract()); | ||||||||||
| 648 | } | ||||||||||
| 649 | return *this; | ||||||||||
| 650 | } | ||||||||||
| 651 | |||||||||||
| 652 | template <typename Func> | ||||||||||
| 653 | constexpr Maybe& apply(Func&& aFunc) const&& { | ||||||||||
| 654 | if (isSome()) { | ||||||||||
| 655 | std::forward<Func>(aFunc)(extract()); | ||||||||||
| 656 | } | ||||||||||
| 657 | return *this; | ||||||||||
| 658 | } | ||||||||||
| 659 | |||||||||||
| 660 | /* | ||||||||||
| 661 | * If |isSome()|, runs the provided function and returns the result wrapped | ||||||||||
| 662 | * in a Maybe. If |isNothing()|, returns an empty Maybe value with the same | ||||||||||
| 663 | * value type as what the provided function would have returned. | ||||||||||
| 664 | */ | ||||||||||
| 665 | template <typename Func> | ||||||||||
| 666 | constexpr auto map(Func&& aFunc) & { | ||||||||||
| 667 | if (isSome()) { | ||||||||||
| 668 | return Some(std::forward<Func>(aFunc)(ref())); | ||||||||||
| 669 | } | ||||||||||
| 670 | return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{}; | ||||||||||
| 671 | } | ||||||||||
| 672 | |||||||||||
| 673 | template <typename Func> | ||||||||||
| 674 | constexpr auto map(Func&& aFunc) const& { | ||||||||||
| 675 | if (isSome()) { | ||||||||||
| 676 | return Some(std::forward<Func>(aFunc)(ref())); | ||||||||||
| 677 | } | ||||||||||
| 678 | return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{}; | ||||||||||
| 679 | } | ||||||||||
| 680 | |||||||||||
| 681 | template <typename Func> | ||||||||||
| 682 | constexpr auto map(Func&& aFunc) && { | ||||||||||
| 683 | if (isSome()) { | ||||||||||
| 684 | return Some(std::forward<Func>(aFunc)(extract())); | ||||||||||
| 685 | } | ||||||||||
| 686 | return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{}; | ||||||||||
| 687 | } | ||||||||||
| 688 | |||||||||||
| 689 | template <typename Func> | ||||||||||
| 690 | constexpr auto map(Func&& aFunc) const&& { | ||||||||||
| 691 | if (isSome()) { | ||||||||||
| 692 | return Some(std::forward<Func>(aFunc)(extract())); | ||||||||||
| 693 | } | ||||||||||
| 694 | return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{}; | ||||||||||
| 695 | } | ||||||||||
| 696 | |||||||||||
| 697 | /* | ||||||||||
| 698 | * If |isSome()|, runs the provided function or functor on the contents of | ||||||||||
| 699 | * this Maybe and returns the result. Note that the provided function or | ||||||||||
| 700 | * functor must return a Maybe<U> of any type U. | ||||||||||
| 701 | * If |isNothing()|, returns an empty Maybe value with the same type as what | ||||||||||
| 702 | * the provided function would have returned. | ||||||||||
| 703 | */ | ||||||||||
| 704 | template <typename Func> | ||||||||||
| 705 | constexpr auto andThen(Func&& aFunc) & { | ||||||||||
| 706 | static_assert(std::is_invocable_v<Func, T&>); | ||||||||||
| 707 | using U = std::invoke_result_t<Func, T&>; | ||||||||||
| 708 | static_assert(detail::IsMaybe<U>::value); | ||||||||||
| 709 | if (isSome()) { | ||||||||||
| 710 | return std::invoke(std::forward<Func>(aFunc), ref()); | ||||||||||
| 711 | } | ||||||||||
| 712 | return std::remove_cv_t<std::remove_reference_t<U>>{}; | ||||||||||
| 713 | } | ||||||||||
| 714 | |||||||||||
| 715 | template <typename Func> | ||||||||||
| 716 | constexpr auto andThen(Func&& aFunc) const& { | ||||||||||
| 717 | static_assert(std::is_invocable_v<Func, const T&>); | ||||||||||
| 718 | using U = std::invoke_result_t<Func, const T&>; | ||||||||||
| 719 | static_assert(detail::IsMaybe<U>::value); | ||||||||||
| 720 | if (isSome()) { | ||||||||||
| 721 | return std::invoke(std::forward<Func>(aFunc), ref()); | ||||||||||
| 722 | } | ||||||||||
| 723 | return std::remove_cv_t<std::remove_reference_t<U>>{}; | ||||||||||
| 724 | } | ||||||||||
| 725 | |||||||||||
| 726 | template <typename Func> | ||||||||||
| 727 | constexpr auto andThen(Func&& aFunc) && { | ||||||||||
| 728 | static_assert(std::is_invocable_v<Func, T&&>); | ||||||||||
| 729 | using U = std::invoke_result_t<Func, T&&>; | ||||||||||
| 730 | static_assert(detail::IsMaybe<U>::value); | ||||||||||
| 731 | if (isSome()) { | ||||||||||
| 732 | return std::invoke(std::forward<Func>(aFunc), extract()); | ||||||||||
| 733 | } | ||||||||||
| 734 | return std::remove_cv_t<std::remove_reference_t<U>>{}; | ||||||||||
| 735 | } | ||||||||||
| 736 | |||||||||||
| 737 | template <typename Func> | ||||||||||
| 738 | constexpr auto andThen(Func&& aFunc) const&& { | ||||||||||
| 739 | static_assert(std::is_invocable_v<Func, const T&&>); | ||||||||||
| 740 | using U = std::invoke_result_t<Func, const T&&>; | ||||||||||
| 741 | static_assert(detail::IsMaybe<U>::value); | ||||||||||
| 742 | if (isSome()) { | ||||||||||
| 743 | return std::invoke(std::forward<Func>(aFunc), extract()); | ||||||||||
| 744 | } | ||||||||||
| 745 | return std::remove_cv_t<std::remove_reference_t<U>>{}; | ||||||||||
| 746 | } | ||||||||||
| 747 | |||||||||||
| 748 | /* | ||||||||||
| 749 | * If |isNothing()|, runs the provided function or functor and returns its | ||||||||||
| 750 | * result. If |isSome()|, returns the contained value wrapped in a Maybe. | ||||||||||
| 751 | */ | ||||||||||
| 752 | template <typename Func> | ||||||||||
| 753 | constexpr Maybe orElse(Func&& aFunc) & { | ||||||||||
| 754 | static_assert(std::is_invocable_v<Func>); | ||||||||||
| 755 | using U = std::invoke_result_t<Func>; | ||||||||||
| 756 | static_assert( | ||||||||||
| 757 | std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>); | ||||||||||
| 758 | if (isSome()) { | ||||||||||
| 759 | return *this; | ||||||||||
| 760 | } | ||||||||||
| 761 | return std::invoke(std::forward<Func>(aFunc)); | ||||||||||
| 762 | } | ||||||||||
| 763 | |||||||||||
| 764 | template <typename Func> | ||||||||||
| 765 | constexpr Maybe orElse(Func&& aFunc) const& { | ||||||||||
| 766 | static_assert(std::is_invocable_v<Func>); | ||||||||||
| 767 | using U = std::invoke_result_t<Func>; | ||||||||||
| 768 | static_assert( | ||||||||||
| 769 | std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>); | ||||||||||
| 770 | if (isSome()) { | ||||||||||
| 771 | return *this; | ||||||||||
| 772 | } | ||||||||||
| 773 | return std::invoke(std::forward<Func>(aFunc)); | ||||||||||
| 774 | } | ||||||||||
| 775 | |||||||||||
| 776 | template <typename Func> | ||||||||||
| 777 | constexpr Maybe orElse(Func&& aFunc) && { | ||||||||||
| 778 | static_assert(std::is_invocable_v<Func>); | ||||||||||
| 779 | using U = std::invoke_result_t<Func>; | ||||||||||
| 780 | static_assert( | ||||||||||
| 781 | std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>); | ||||||||||
| 782 | if (isSome()) { | ||||||||||
| 783 | return std::move(*this); | ||||||||||
| 784 | } | ||||||||||
| 785 | return std::invoke(std::forward<Func>(aFunc)); | ||||||||||
| 786 | } | ||||||||||
| 787 | |||||||||||
| 788 | template <typename Func> | ||||||||||
| 789 | constexpr Maybe orElse(Func&& aFunc) const&& { | ||||||||||
| 790 | static_assert(std::is_invocable_v<Func>); | ||||||||||
| 791 | using U = std::invoke_result_t<Func>; | ||||||||||
| 792 | static_assert( | ||||||||||
| 793 | std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>); | ||||||||||
| 794 | if (isSome()) { | ||||||||||
| 795 | return std::move(*this); | ||||||||||
| 796 | } | ||||||||||
| 797 | return std::invoke(std::forward<Func>(aFunc)); | ||||||||||
| 798 | } | ||||||||||
| 799 | |||||||||||
| 800 | /* If |isSome()|, empties this Maybe and destroys its contents. */ | ||||||||||
| 801 | constexpr void reset() { | ||||||||||
| 802 | if (isSome()) { | ||||||||||
| 803 | if constexpr (!std::is_trivially_destructible_v<T>) { | ||||||||||
| 804 | /* | ||||||||||
| 805 | * Static analyzer gets confused if we have Maybe<MutexAutoLock>, | ||||||||||
| 806 | * so we suppress thread-safety warnings here | ||||||||||
| 807 | */ | ||||||||||
| 808 | MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push
GCC diagnostic ignored "-Wthread-safety" | ||||||||||
| 809 | ref().T::~T(); | ||||||||||
| 810 | MOZ_POP_THREAD_SAFETYGCC diagnostic pop | ||||||||||
| 811 | poisonData(); | ||||||||||
| 812 | } | ||||||||||
| 813 | mIsSome = false; | ||||||||||
| 814 | } | ||||||||||
| 815 | } | ||||||||||
| 816 | |||||||||||
| 817 | /* | ||||||||||
| 818 | * Constructs a T value in-place in this empty Maybe<T>'s storage. The | ||||||||||
| 819 | * arguments to |emplace()| are the parameters to T's constructor. | ||||||||||
| 820 | */ | ||||||||||
| 821 | template <typename... Args> | ||||||||||
| 822 | constexpr void emplace(Args&&... aArgs); | ||||||||||
| 823 | |||||||||||
| 824 | template <typename U> | ||||||||||
| 825 | constexpr std::enable_if_t<std::is_same_v<T, U> && | ||||||||||
| 826 | std::is_copy_constructible_v<U> && | ||||||||||
| 827 | !std::is_move_constructible_v<U>> | ||||||||||
| 828 | emplace(U&& aArgs) { | ||||||||||
| 829 | emplace(aArgs); | ||||||||||
| 830 | } | ||||||||||
| 831 | |||||||||||
| 832 | friend std::ostream& operator<<(std::ostream& aStream, | ||||||||||
| 833 | const Maybe<T>& aMaybe) { | ||||||||||
| 834 | if (aMaybe) { | ||||||||||
| 835 | aStream << aMaybe.ref(); | ||||||||||
| 836 | } else { | ||||||||||
| 837 | aStream << "<Nothing>"; | ||||||||||
| 838 | } | ||||||||||
| 839 | return aStream; | ||||||||||
| 840 | } | ||||||||||
| 841 | }; | ||||||||||
| 842 | |||||||||||
| 843 | template <typename T> | ||||||||||
| 844 | class Maybe<T&> { | ||||||||||
| 845 | public: | ||||||||||
| 846 | constexpr Maybe() = default; | ||||||||||
| 847 | constexpr MOZ_IMPLICIT Maybe(Nothing) {} | ||||||||||
| 848 | |||||||||||
| 849 | void emplace(T& aRef) { mValue = &aRef; } | ||||||||||
| 850 | |||||||||||
| 851 | /* Methods that check whether this Maybe contains a value */ | ||||||||||
| 852 | constexpr explicit operator bool() const { return isSome(); } | ||||||||||
| 853 | constexpr bool isSome() const { return mValue; } | ||||||||||
| 854 | constexpr bool isNothing() const { return !mValue; } | ||||||||||
| 855 | |||||||||||
| 856 | T& ref() const { | ||||||||||
| 857 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 857); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 857; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 858 | return *mValue; | ||||||||||
| 859 | } | ||||||||||
| 860 | |||||||||||
| 861 | T* operator->() const { return &ref(); } | ||||||||||
| 862 | T& operator*() const { return ref(); } | ||||||||||
| 863 | |||||||||||
| 864 | // Deliberately not defining value and ptr accessors, as these may be | ||||||||||
| 865 | // confusing on a reference-typed Maybe. | ||||||||||
| 866 | |||||||||||
| 867 | // XXX Should we define refOr? | ||||||||||
| 868 | |||||||||||
| 869 | void reset() { mValue = nullptr; } | ||||||||||
| 870 | |||||||||||
| 871 | template <typename Func> | ||||||||||
| 872 | const Maybe& apply(Func&& aFunc) const { | ||||||||||
| 873 | if (isSome()) { | ||||||||||
| 874 | std::forward<Func>(aFunc)(ref()); | ||||||||||
| 875 | } | ||||||||||
| 876 | return *this; | ||||||||||
| 877 | } | ||||||||||
| 878 | |||||||||||
| 879 | template <typename Func> | ||||||||||
| 880 | auto map(Func&& aFunc) const { | ||||||||||
| 881 | Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val; | ||||||||||
| 882 | if (isSome()) { | ||||||||||
| 883 | val.emplace(std::forward<Func>(aFunc)(ref())); | ||||||||||
| 884 | } | ||||||||||
| 885 | return val; | ||||||||||
| 886 | } | ||||||||||
| 887 | |||||||||||
| 888 | template <typename Func> | ||||||||||
| 889 | constexpr auto andThen(Func&& aFunc) const { | ||||||||||
| 890 | static_assert(std::is_invocable_v<Func, T&>); | ||||||||||
| 891 | using U = std::invoke_result_t<Func, T&>; | ||||||||||
| 892 | static_assert(detail::IsMaybe<U>::value); | ||||||||||
| 893 | if (isSome()) { | ||||||||||
| 894 | return std::invoke(std::forward<Func>(aFunc), ref()); | ||||||||||
| 895 | } | ||||||||||
| 896 | return std::remove_cv_t<std::remove_reference_t<U>>{}; | ||||||||||
| 897 | } | ||||||||||
| 898 | |||||||||||
| 899 | template <typename Func> | ||||||||||
| 900 | constexpr Maybe orElse(Func&& aFunc) const { | ||||||||||
| 901 | static_assert(std::is_invocable_v<Func>); | ||||||||||
| 902 | using U = std::invoke_result_t<Func>; | ||||||||||
| 903 | static_assert( | ||||||||||
| 904 | std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>); | ||||||||||
| 905 | if (isSome()) { | ||||||||||
| 906 | return *this; | ||||||||||
| 907 | } | ||||||||||
| 908 | return std::invoke(std::forward<Func>(aFunc)); | ||||||||||
| 909 | } | ||||||||||
| 910 | |||||||||||
| 911 | bool refEquals(const Maybe<T&>& aOther) const { | ||||||||||
| 912 | return mValue == aOther.mValue; | ||||||||||
| 913 | } | ||||||||||
| 914 | |||||||||||
| 915 | bool refEquals(const T& aOther) const { return mValue == &aOther; } | ||||||||||
| 916 | |||||||||||
| 917 | private: | ||||||||||
| 918 | T* mValue = nullptr; | ||||||||||
| 919 | }; | ||||||||||
| 920 | |||||||||||
| 921 | template <typename T> | ||||||||||
| 922 | constexpr T Maybe<T>::value() const& { | ||||||||||
| 923 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 923); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 923; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 924 | return ref(); | ||||||||||
| 925 | } | ||||||||||
| 926 | |||||||||||
| 927 | template <typename T> | ||||||||||
| 928 | constexpr T Maybe<T>::value() && { | ||||||||||
| 929 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 929); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 929; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 930 | return std::move(ref()); | ||||||||||
| 931 | } | ||||||||||
| 932 | |||||||||||
| 933 | template <typename T> | ||||||||||
| 934 | constexpr T Maybe<T>::value() const&& { | ||||||||||
| 935 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 935); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 935; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 936 | return std::move(ref()); | ||||||||||
| 937 | } | ||||||||||
| 938 | |||||||||||
| 939 | template <typename T> | ||||||||||
| 940 | T* Maybe<T>::ptr() { | ||||||||||
| 941 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 941); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 941; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 942 | return &ref(); | ||||||||||
| 943 | } | ||||||||||
| 944 | |||||||||||
| 945 | template <typename T> | ||||||||||
| 946 | constexpr const T* Maybe<T>::ptr() const { | ||||||||||
| 947 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 947); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 947; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 948 | return &ref(); | ||||||||||
| 949 | } | ||||||||||
| 950 | |||||||||||
| 951 | template <typename T> | ||||||||||
| 952 | constexpr T* Maybe<T>::operator->() { | ||||||||||
| 953 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 953); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 953; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 954 | return ptr(); | ||||||||||
| 955 | } | ||||||||||
| 956 | |||||||||||
| 957 | template <typename T> | ||||||||||
| 958 | constexpr const T* Maybe<T>::operator->() const { | ||||||||||
| 959 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 959); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 959; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 960 | return ptr(); | ||||||||||
| 961 | } | ||||||||||
| 962 | |||||||||||
| 963 | template <typename T> | ||||||||||
| 964 | constexpr T& Maybe<T>::ref() & { | ||||||||||
| 965 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 965); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 965; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 966 | return mStorage.val; | ||||||||||
| 967 | } | ||||||||||
| 968 | |||||||||||
| 969 | template <typename T> | ||||||||||
| 970 | constexpr const T& Maybe<T>::ref() const& { | ||||||||||
| 971 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 971); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 971; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 972 | return mStorage.val; | ||||||||||
| 973 | } | ||||||||||
| 974 | |||||||||||
| 975 | template <typename T> | ||||||||||
| 976 | constexpr T&& Maybe<T>::ref() && { | ||||||||||
| 977 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 977); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 977; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 978 | return std::move(mStorage.val); | ||||||||||
| 979 | } | ||||||||||
| 980 | |||||||||||
| 981 | template <typename T> | ||||||||||
| 982 | constexpr const T&& Maybe<T>::ref() const&& { | ||||||||||
| 983 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 983); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 983; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 984 | return std::move(mStorage.val); | ||||||||||
| 985 | } | ||||||||||
| 986 | |||||||||||
| 987 | template <typename T> | ||||||||||
| 988 | constexpr T& Maybe<T>::operator*() & { | ||||||||||
| 989 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 989); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 989; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 990 | return ref(); | ||||||||||
| 991 | } | ||||||||||
| 992 | |||||||||||
| 993 | template <typename T> | ||||||||||
| 994 | constexpr const T& Maybe<T>::operator*() const& { | ||||||||||
| 995 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 995); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 995; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 996 | return ref(); | ||||||||||
| 997 | } | ||||||||||
| 998 | |||||||||||
| 999 | template <typename T> | ||||||||||
| 1000 | constexpr T&& Maybe<T>::operator*() && { | ||||||||||
| 1001 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 1001); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 1001; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 1002 | return std::move(ref()); | ||||||||||
| 1003 | } | ||||||||||
| 1004 | |||||||||||
| 1005 | template <typename T> | ||||||||||
| 1006 | constexpr const T&& Maybe<T>::operator*() const&& { | ||||||||||
| 1007 | MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 1007); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()" ")"); do { *((volatile int*)__null) = 1007; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 1008 | return std::move(ref()); | ||||||||||
| 1009 | } | ||||||||||
| 1010 | |||||||||||
| 1011 | template <typename T> | ||||||||||
| 1012 | template <typename... Args> | ||||||||||
| 1013 | constexpr void Maybe<T>::emplace(Args&&... aArgs) { | ||||||||||
| 1014 | MOZ_RELEASE_ASSERT(!isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!isSome()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h" , 1014); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!isSome()" ")"); do { *((volatile int*)__null) = 1014; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | ||||||||||
| 1015 | ::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...); | ||||||||||
| 1016 | mIsSome = true; | ||||||||||
| 1017 | } | ||||||||||
| 1018 | |||||||||||
| 1019 | /* | ||||||||||
| 1020 | * Some() creates a Maybe<T> value containing the provided T value. If T has a | ||||||||||
| 1021 | * move constructor, it's used to make this as efficient as possible. | ||||||||||
| 1022 | * | ||||||||||
| 1023 | * Some() selects the type of Maybe it returns by removing any const, volatile, | ||||||||||
| 1024 | * or reference qualifiers from the type of the value you pass to it. This gives | ||||||||||
| 1025 | * it more intuitive behavior when used in expressions, but it also means that | ||||||||||
| 1026 | * if you need to construct a Maybe value that holds a const, volatile, or | ||||||||||
| 1027 | * reference value, you need to use emplace() instead. | ||||||||||
| 1028 | */ | ||||||||||
| 1029 | template <typename T, typename U> | ||||||||||
| 1030 | constexpr Maybe<U> Some(T&& aValue) { | ||||||||||
| 1031 | return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}}; | ||||||||||
| 1032 | } | ||||||||||
| 1033 | |||||||||||
| 1034 | template <typename T> | ||||||||||
| 1035 | constexpr Maybe<T&> SomeRef(T& aValue) { | ||||||||||
| 1036 | Maybe<T&> value; | ||||||||||
| 1037 | value.emplace(aValue); | ||||||||||
| 1038 | return value; | ||||||||||
| 1039 | } | ||||||||||
| 1040 | |||||||||||
| 1041 | template <typename T> | ||||||||||
| 1042 | constexpr Maybe<T&> ToMaybeRef(T* const aPtr) { | ||||||||||
| 1043 | return aPtr ? SomeRef(*aPtr) : Nothing{}; | ||||||||||
| 1044 | } | ||||||||||
| 1045 | |||||||||||
| 1046 | template <typename T> | ||||||||||
| 1047 | Maybe<std::remove_cv_t<std::remove_reference_t<T>>> ToMaybe(T* aPtr) { | ||||||||||
| 1048 | if (aPtr) { | ||||||||||
| 1049 | return Some(*aPtr); | ||||||||||
| 1050 | } | ||||||||||
| 1051 | return Nothing(); | ||||||||||
| 1052 | } | ||||||||||
| 1053 | |||||||||||
| 1054 | /* | ||||||||||
| 1055 | * Two Maybe<T> values are equal if | ||||||||||
| 1056 | * - both are Nothing, or | ||||||||||
| 1057 | * - both are Some, and the values they contain are equal. | ||||||||||
| 1058 | */ | ||||||||||
| 1059 | template <typename T> | ||||||||||
| 1060 | constexpr bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1061 | static_assert(!std::is_reference_v<T>, | ||||||||||
| 1062 | "operator== is not defined for Maybe<T&>, compare values or " | ||||||||||
| 1063 | "addresses explicitly instead"); | ||||||||||
| 1064 | if (aLHS.isNothing() != aRHS.isNothing()) { | ||||||||||
| 1065 | return false; | ||||||||||
| 1066 | } | ||||||||||
| 1067 | return aLHS.isNothing() || *aLHS == *aRHS; | ||||||||||
| 1068 | } | ||||||||||
| 1069 | |||||||||||
| 1070 | template <typename T> | ||||||||||
| 1071 | constexpr bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1072 | return !(aLHS == aRHS); | ||||||||||
| 1073 | } | ||||||||||
| 1074 | |||||||||||
| 1075 | /* | ||||||||||
| 1076 | * We support comparison to Nothing to allow reasonable expressions like: | ||||||||||
| 1077 | * if (maybeValue == Nothing()) { ... } | ||||||||||
| 1078 | */ | ||||||||||
| 1079 | template <typename T> | ||||||||||
| 1080 | constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) { | ||||||||||
| 1081 | return aLHS.isNothing(); | ||||||||||
| 1082 | } | ||||||||||
| 1083 | |||||||||||
| 1084 | template <typename T> | ||||||||||
| 1085 | constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) { | ||||||||||
| 1086 | return !(aLHS == aRHS); | ||||||||||
| 1087 | } | ||||||||||
| 1088 | |||||||||||
| 1089 | template <typename T> | ||||||||||
| 1090 | constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1091 | return aRHS.isNothing(); | ||||||||||
| 1092 | } | ||||||||||
| 1093 | |||||||||||
| 1094 | template <typename T> | ||||||||||
| 1095 | constexpr bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1096 | return !(aLHS == aRHS); | ||||||||||
| 1097 | } | ||||||||||
| 1098 | |||||||||||
| 1099 | /* | ||||||||||
| 1100 | * Maybe<T> values are ordered in the same way T values are ordered, except that | ||||||||||
| 1101 | * Nothing comes before anything else. | ||||||||||
| 1102 | */ | ||||||||||
| 1103 | template <typename T> | ||||||||||
| 1104 | constexpr bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1105 | if (aLHS.isNothing()) { | ||||||||||
| 1106 | return aRHS.isSome(); | ||||||||||
| 1107 | } | ||||||||||
| 1108 | if (aRHS.isNothing()) { | ||||||||||
| 1109 | return false; | ||||||||||
| 1110 | } | ||||||||||
| 1111 | return *aLHS < *aRHS; | ||||||||||
| 1112 | } | ||||||||||
| 1113 | |||||||||||
| 1114 | template <typename T> | ||||||||||
| 1115 | constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1116 | return !(aLHS < aRHS || aLHS == aRHS); | ||||||||||
| 1117 | } | ||||||||||
| 1118 | |||||||||||
| 1119 | template <typename T> | ||||||||||
| 1120 | constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1121 | return aLHS < aRHS || aLHS == aRHS; | ||||||||||
| 1122 | } | ||||||||||
| 1123 | |||||||||||
| 1124 | template <typename T> | ||||||||||
| 1125 | constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) { | ||||||||||
| 1126 | return !(aLHS < aRHS); | ||||||||||
| 1127 | } | ||||||||||
| 1128 | |||||||||||
| 1129 | template <typename T> | ||||||||||
| 1130 | inline void ImplCycleCollectionTraverse( | ||||||||||
| 1131 | nsCycleCollectionTraversalCallback& aCallback, mozilla::Maybe<T>& aField, | ||||||||||
| 1132 | const char* aName, uint32_t aFlags = 0) { | ||||||||||
| 1133 | if (aField) { | ||||||||||
| 1134 | ImplCycleCollectionTraverse(aCallback, aField.ref(), aName, aFlags); | ||||||||||
| 1135 | } | ||||||||||
| 1136 | } | ||||||||||
| 1137 | |||||||||||
| 1138 | template <typename T> | ||||||||||
| 1139 | inline void ImplCycleCollectionUnlink(mozilla::Maybe<T>& aField) { | ||||||||||
| 1140 | if (aField) { | ||||||||||
| 1141 | ImplCycleCollectionUnlink(aField.ref()); | ||||||||||
| 1142 | } | ||||||||||
| 1143 | } | ||||||||||
| 1144 | |||||||||||
| 1145 | } // namespace mozilla | ||||||||||
| 1146 | |||||||||||
| 1147 | #endif /* mozilla_Maybe_h */ |
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ | |||
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
| 6 | ||||
| 7 | /* A type that can be sent without needing to make a copy during | |||
| 8 | * serialization. In addition the receiver can take ownership of the | |||
| 9 | * data to avoid having to make an additional copy. */ | |||
| 10 | ||||
| 11 | #ifndef mozilla_ipc_ByteBuf_h | |||
| 12 | #define mozilla_ipc_ByteBuf_h | |||
| 13 | ||||
| 14 | #include "mozilla/Assertions.h" | |||
| 15 | ||||
| 16 | namespace IPC { | |||
| 17 | template <typename T> | |||
| 18 | struct ParamTraits; | |||
| 19 | } | |||
| 20 | ||||
| 21 | namespace mozilla { | |||
| 22 | ||||
| 23 | namespace ipc { | |||
| 24 | ||||
| 25 | class ByteBuf final { | |||
| 26 | friend struct IPC::ParamTraits<mozilla::ipc::ByteBuf>; | |||
| 27 | ||||
| 28 | public: | |||
| 29 | bool Allocate(size_t aLength) { | |||
| 30 | MOZ_ASSERT(mData == nullptr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mData == nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mData == nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mData == nullptr" , "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/ipc/ByteBuf.h" , 30); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mData == nullptr" ")"); do { *((volatile int*)__null) = 30; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 31 | mData = (uint8_t*)malloc(aLength); | |||
| 32 | if (!mData) { | |||
| 33 | return false; | |||
| 34 | } | |||
| 35 | mLen = aLength; | |||
| 36 | mCapacity = aLength; | |||
| 37 | return true; | |||
| 38 | } | |||
| 39 | ||||
| 40 | ByteBuf() : mData(nullptr), mLen(0), mCapacity(0) {} | |||
| 41 | ||||
| 42 | ByteBuf(uint8_t* aData, size_t aLen, size_t aCapacity) | |||
| 43 | : mData(aData), mLen(aLen), mCapacity(aCapacity) {} | |||
| 44 | ||||
| 45 | ByteBuf(const ByteBuf& aFrom) = delete; | |||
| 46 | ||||
| 47 | ByteBuf(ByteBuf&& aFrom) | |||
| 48 | : mData(aFrom.mData), mLen(aFrom.mLen), mCapacity(aFrom.mCapacity) { | |||
| 49 | aFrom.mData = nullptr; | |||
| 50 | aFrom.mLen = 0; | |||
| 51 | aFrom.mCapacity = 0; | |||
| 52 | } | |||
| 53 | ||||
| 54 | ByteBuf& operator=(ByteBuf&& aFrom) { | |||
| 55 | std::swap(mData, aFrom.mData); | |||
| 56 | std::swap(mLen, aFrom.mLen); | |||
| 57 | std::swap(mCapacity, aFrom.mCapacity); | |||
| 58 | return *this; | |||
| 59 | } | |||
| 60 | ||||
| 61 | ~ByteBuf() { free(mData); } | |||
| ||||
| 62 | ||||
| 63 | uint8_t* mData; | |||
| 64 | size_t mLen; | |||
| 65 | size_t mCapacity; | |||
| 66 | }; | |||
| 67 | ||||
| 68 | } // namespace ipc | |||
| 69 | } // namespace mozilla | |||
| 70 | ||||
| 71 | #endif // ifndef mozilla_ipc_ByteBuf_h |
| 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | /* Internal storage class used e.g. by Maybe and Result. This file doesn't |
| 8 | * contain any public declarations. */ |
| 9 | |
| 10 | #ifndef mfbt_MaybeStorageBase_h |
| 11 | #define mfbt_MaybeStorageBase_h |
| 12 | |
| 13 | #include <type_traits> |
| 14 | #include <utility> |
| 15 | |
| 16 | namespace mozilla::detail { |
| 17 | |
| 18 | template <typename T> |
| 19 | constexpr bool IsTriviallyDestructibleAndCopyable = |
| 20 | std::is_trivially_destructible_v<T> && |
| 21 | (std::is_trivially_copy_constructible_v<T> || |
| 22 | !std::is_copy_constructible_v<T>); |
| 23 | |
| 24 | template <typename T, bool TriviallyDestructibleAndCopyable = |
| 25 | IsTriviallyDestructibleAndCopyable<T>> |
| 26 | struct MaybeStorageBase; |
| 27 | |
| 28 | template <typename T> |
| 29 | struct MaybeStorageBase<T, false> { |
| 30 | protected: |
| 31 | using NonConstT = std::remove_const_t<T>; |
| 32 | |
| 33 | union Union { |
| 34 | Union() {} |
| 35 | explicit Union(const T& aVal) : val{aVal} {} |
| 36 | template <typename U, |
| 37 | typename = std::enable_if_t<std::is_move_constructible_v<U>>> |
| 38 | explicit Union(U&& aVal) : val{std::forward<U>(aVal)} {} |
| 39 | template <typename... Args> |
| 40 | explicit Union(std::in_place_t, Args&&... aArgs) |
| 41 | : val{std::forward<Args>(aArgs)...} {} |
| 42 | |
| 43 | ~Union() {} |
| 44 | |
| 45 | NonConstT val; |
| 46 | } mStorage; |
| 47 | |
| 48 | public: |
| 49 | constexpr MaybeStorageBase() = default; |
| 50 | explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {} |
| 51 | explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {} |
| 52 | template <typename... Args> |
| 53 | explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs) |
| 54 | : mStorage{std::in_place, std::forward<Args>(aArgs)...} {} |
| 55 | |
| 56 | const T* addr() const { return &mStorage.val; } |
| 57 | T* addr() { return &mStorage.val; } |
| 58 | }; |
| 59 | |
| 60 | template <typename T> |
| 61 | struct MaybeStorageBase<T, true> { |
| 62 | protected: |
| 63 | using NonConstT = std::remove_const_t<T>; |
| 64 | |
| 65 | union Union { |
| 66 | constexpr Union() : empty() {} |
| 67 | constexpr explicit Union(const T& aVal) : val{aVal} {} |
| 68 | constexpr explicit Union(T&& aVal) : val{std::move(aVal)} {} |
| 69 | template <typename... Args> |
| 70 | constexpr explicit Union(std::in_place_t, Args&&... aArgs) |
| 71 | : val{std::forward<Args>(aArgs)...} {} |
| 72 | |
| 73 | NonConstT val; |
| 74 | char empty; |
| 75 | } mStorage; |
| 76 | |
| 77 | public: |
| 78 | constexpr MaybeStorageBase() = default; |
| 79 | constexpr explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {} |
| 80 | constexpr explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {} |
| 81 | |
| 82 | template <typename... Args> |
| 83 | constexpr explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs) |
| 84 | : mStorage{std::in_place, std::forward<Args>(aArgs)...} {} |
| 85 | |
| 86 | constexpr const T* addr() const { return &mStorage.val; } |
| 87 | constexpr T* addr() { return &mStorage.val; } |
| 88 | }; |
| 89 | |
| 90 | } // namespace mozilla::detail |
| 91 | |
| 92 | #endif |