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 |