diff --git a/android/features/tab_ui/BUILD.gn b/android/features/tab_ui/BUILD.gn index e968e7be00f6..b07c562d9d3d 100644 --- a/android/features/tab_ui/BUILD.gn +++ b/android/features/tab_ui/BUILD.gn @@ -17,9 +17,11 @@ android_library("java") { "//chrome/android/features/tab_ui:tab_suggestions_java", "//chrome/browser/android/lifecycle:java", "//chrome/browser/browser_controls/android:java", + "//chrome/browser/commerce/merchant_viewer/android:java", "//chrome/browser/flags:java", "//chrome/browser/preferences:java", "//chrome/browser/tabmodel:java", + "//chrome/browser/ui/android/layouts:java", "//chrome/browser/ui/android/theme:java", "//chrome/browser/ui/android/toolbar:java", "//chrome/browser/ui/messages/android:java", diff --git a/android/java/apk_for_test.flags b/android/java/apk_for_test.flags index 64d6070d0ac2..be25b55d517d 100644 --- a/android/java/apk_for_test.flags +++ b/android/java/apk_for_test.flags @@ -70,15 +70,6 @@ public (...); } --keep class org.chromium.chrome.browser.omnibox.suggestions.editurl.EditUrlSuggestionProcessor { - public (...); - *** mHasClearedOmniboxForFocus; -} - --keep class org.chromium.chrome.browser.omnibox.suggestions.editurl.BraveEditUrlSuggestionProcessor { - public (...); -} - -keep class org.chromium.chrome.browser.sync.settings.ManageSyncSettings { *** mGoogleActivityControls; *** mSyncEncryption; @@ -590,6 +581,7 @@ *** mIsTablet; *** mNativeInitialized; *** mIsLocationBarFocusedFromNtpScroll; + *** mShouldClearOmniboxOnFocus; *** mContext; *** mBrandedColorScheme; *** mAssistantVoiceSearchServiceSupplier; diff --git a/android/java/org/chromium/chrome/browser/BraveApplicationImplBase.java b/android/java/org/chromium/chrome/browser/BraveApplicationImplBase.java index e107e54df6a1..6cb3363bcef1 100644 --- a/android/java/org/chromium/chrome/browser/BraveApplicationImplBase.java +++ b/android/java/org/chromium/chrome/browser/BraveApplicationImplBase.java @@ -25,7 +25,7 @@ public void alwaysOnTriggered() { } }); // Set a handler for SafeBrowsing. It has to be done only once for a process lifetime. - SafeBrowsingApiBridge.setHandler(BraveSafeBrowsingApiHandler.getInstance()); + SafeBrowsingApiBridge.setSafetyNetApiHandler(BraveSafeBrowsingApiHandler.getInstance()); } } } diff --git a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkManagerMediator.java b/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkManagerMediator.java index d01798814b6a..63c42daef183 100644 --- a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkManagerMediator.java +++ b/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkManagerMediator.java @@ -18,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.OnScrollListener; import org.chromium.base.Log; import org.chromium.base.supplier.ObservableSupplierImpl; @@ -40,6 +41,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.function.Consumer; class BraveBookmarkManagerMediator extends BookmarkManagerMediator implements BraveBookmarkDelegate { @@ -61,12 +63,12 @@ class BraveBookmarkManagerMediator BookmarkUndoController bookmarkUndoController, ModelList modelList, BookmarkUiPrefs bookmarkUiPrefs, Runnable hideKeyboardRunnable, BookmarkImageFetcher bookmarkImageFetcher, ShoppingService shoppingService, - SnackbarManager snackbarManager) { + SnackbarManager snackbarManager, Consumer onScrollListenerConsumer) { super(context, bookmarkModel, bookmarkOpener, selectableListLayout, selectionDelegate, recyclerView, dragReorderableRecyclerViewAdapter, largeIconBridge, isDialogUi, isIncognito, backPressStateSupplier, profile, bookmarkUndoController, modelList, bookmarkUiPrefs, hideKeyboardRunnable, bookmarkImageFetcher, shoppingService, - snackbarManager); + snackbarManager, onScrollListenerConsumer); } public void setWindow(ActivityWindowAndroid window) { diff --git a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkToolbarCoordinator.java b/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkToolbarCoordinator.java index 7f05ab133da6..a66685bd6c27 100644 --- a/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkToolbarCoordinator.java +++ b/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkToolbarCoordinator.java @@ -25,10 +25,12 @@ class BraveBookmarkToolbarCoordinator extends BookmarkToolbarCoordinator { DragReorderableRecyclerViewAdapter dragReorderableRecyclerViewAdapter, boolean isDialogUi, OneshotSupplier bookmarkDelegateSupplier, BookmarkModel bookmarkModel, BookmarkOpener bookmarkOpener, - BookmarkUiPrefs bookmarkUiPrefs, ModalDialogManager modalDialogManager) { + BookmarkUiPrefs bookmarkUiPrefs, ModalDialogManager modalDialogManager, + Runnable endSearchRunnable) { super(context, selectableListLayout, selectionDelegate, searchDelegate, dragReorderableRecyclerViewAdapter, isDialogUi, bookmarkDelegateSupplier, - bookmarkModel, bookmarkOpener, bookmarkUiPrefs, modalDialogManager); + bookmarkModel, bookmarkOpener, bookmarkUiPrefs, modalDialogManager, + endSearchRunnable); if (mToolbar instanceof BraveBookmarkToolbar) { ((BraveBookmarkToolbar) mToolbar).setBraveBookmarkDelegate(bookmarkDelegateSupplier); diff --git a/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java b/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java index db399fee81b8..0ef6908a934c 100644 --- a/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java +++ b/android/java/org/chromium/chrome/browser/ntp/BraveNewTabPageLayout.java @@ -1092,11 +1092,11 @@ public void initialize(NewTabPageManager manager, Activity activity, Delegate ti FeedSurfaceScrollDelegate scrollDelegate, TouchEnabledDelegate touchEnabledDelegate, UiConfig uiConfig, ActivityLifecycleDispatcher lifecycleDispatcher, NewTabPageUma uma, boolean isIncognito, WindowAndroid windowAndroid, boolean isNtpAsHomeSurfaceEnabled, - boolean isSurfacePolishEnabled, boolean isSurfacePolishOmniboxSizeEnabled) { + boolean isSurfacePolishEnabled, boolean isSurfacePolishOmniboxColorEnabled) { super.initialize(manager, activity, tileGroupDelegate, searchProviderHasLogo, searchProviderIsGoogle, scrollDelegate, touchEnabledDelegate, uiConfig, lifecycleDispatcher, uma, isIncognito, windowAndroid, isNtpAsHomeSurfaceEnabled, - isSurfacePolishEnabled, isSurfacePolishOmniboxSizeEnabled); + isSurfacePolishEnabled, isSurfacePolishOmniboxColorEnabled); assert mMvTilesContainerLayout != null : "Something has changed in the upstream!"; diff --git a/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarCoordinator.java b/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarCoordinator.java index f998f3904cba..901b23d93545 100644 --- a/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarCoordinator.java +++ b/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarCoordinator.java @@ -29,6 +29,7 @@ import org.chromium.chrome.browser.share.ShareDelegate; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabWindowManager; import org.chromium.components.omnibox.action.OmniboxActionDelegate; import org.chromium.ui.base.WindowAndroid; @@ -66,7 +67,8 @@ public BraveLocationBarCoordinator(View locationBarLayout, View autocompleteAnch @Nullable BackPressManager backPressManager, @NonNull OmniboxSuggestionsDropdownScrollListener omniboxSuggestionsDropdownScrollListener, - @Nullable OpenHistoryClustersDelegate openHistoryClustersDelegate) { + @Nullable OpenHistoryClustersDelegate openHistoryClustersDelegate, + @Nullable ObservableSupplier tabModelSelectorSupplier) { super(locationBarLayout, autocompleteAnchorView, profileObservableSupplier, privacyPreferencesManager, locationBarDataProvider, actionModeCallback, windowDelegate, windowAndroid, activityTabSupplier, modalDialogManagerSupplier, @@ -76,7 +78,8 @@ public BraveLocationBarCoordinator(View locationBarLayout, View autocompleteAnch tabWindowManagerSupplier, bookmarkState, isToolbarMicEnabledSupplier, merchantTrustSignalsCoordinatorSupplier, omniboxActionDelegate, browserControlsVisibilityDelegate, reportExceptionCallback, backPressManager, - omniboxSuggestionsDropdownScrollListener, openHistoryClustersDelegate); + omniboxSuggestionsDropdownScrollListener, openHistoryClustersDelegate, + tabModelSelectorSupplier); if (mLocationBarMediator instanceof BraveLocationBarMediator) { mQRButton = locationBarLayout.findViewById(R.id.qr_button); diff --git a/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarLayout.java b/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarLayout.java index 358b0361a5c4..e3c5ab8b4d3e 100644 --- a/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarLayout.java +++ b/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarLayout.java @@ -12,6 +12,8 @@ import androidx.core.widget.ImageViewCompat; +import org.chromium.chrome.browser.omnibox.status.StatusView; + public class BraveLocationBarLayout extends LocationBarLayout { private ImageButton mQRButton; @@ -25,6 +27,14 @@ public BraveLocationBarLayout(Context context, AttributeSet attrs, int layoutId) mQRButton = findViewById(R.id.qr_button); } + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + StatusView statusView = findViewById(R.id.location_bar_status); + statusView.setBackgroundDrawable(null); + } + void setQRButtonTint(ColorStateList colorStateList) { ImageViewCompat.setImageTintList(mQRButton, colorStateList); } diff --git a/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarMediator.java b/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarMediator.java index e7c62e048924..544045ab2b0a 100644 --- a/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarMediator.java +++ b/android/java/org/chromium/chrome/browser/omnibox/BraveLocationBarMediator.java @@ -12,6 +12,7 @@ import android.view.View; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import org.chromium.base.supplier.ObservableSupplier; @@ -20,6 +21,7 @@ import org.chromium.chrome.browser.locale.LocaleManager; import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManager; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.theme.ThemeUtils; import org.chromium.chrome.browser.ui.theme.BrandedColorScheme; import org.chromium.components.search_engines.TemplateUrlService; @@ -36,6 +38,7 @@ public class BraveLocationBarMediator extends LocationBarMediator { private boolean mIsTablet; private boolean mNativeInitialized; private boolean mIsLocationBarFocusedFromNtpScroll; + private boolean mShouldClearOmniboxOnFocus; private Context mContext; private @BrandedColorScheme int mBrandedColorScheme = BrandedColorScheme.APP_DEFAULT; @@ -52,12 +55,13 @@ public BraveLocationBarMediator(@NonNull Context context, @NonNull LensController lensController, @NonNull SaveOfflineButtonState saveOfflineButtonState, @NonNull OmniboxUma omniboxUma, @NonNull BooleanSupplier isToolbarMicEnabledSupplier, - @NonNull OmniboxSuggestionsDropdownEmbedderImpl dropdownEmbedder) { + @NonNull OmniboxSuggestionsDropdownEmbedderImpl dropdownEmbedder, + @Nullable ObservableSupplier tabModelSelectorSupplier) { super(context, locationBarLayout, locationBarDataProvider, profileSupplier, privacyPreferencesManager, overrideUrlLoadingDelegate, localeManager, templateUrlServiceSupplier, backKeyBehavior, windowAndroid, isTablet, searchEngineLogoUtils, lensController, saveOfflineButtonState, omniboxUma, - isToolbarMicEnabledSupplier, dropdownEmbedder); + isToolbarMicEnabledSupplier, dropdownEmbedder, tabModelSelectorSupplier); } public static Class getOmniboxUmaClass() { @@ -165,4 +169,11 @@ private void openQRCodeDialog() { "BraveLocationBarQRDialogFragment"); } } + + @Override + /*package */ void onUrlFocusChange(boolean hasFocus) { + // We don't want to clear omnibox for focus. + mShouldClearOmniboxOnFocus = false; + super.onUrlFocusChange(hasFocus); + } } diff --git a/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediator.java b/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediator.java index 7c098553dc0d..9df379e13d8d 100644 --- a/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediator.java +++ b/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediator.java @@ -16,7 +16,6 @@ import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider; import org.chromium.chrome.browser.omnibox.suggestions.basic.BasicSuggestionProcessor.BookmarkState; -import org.chromium.chrome.browser.omnibox.suggestions.brave_search.BraveSearchBannerProcessor; import org.chromium.chrome.browser.omnibox.suggestions.history_clusters.HistoryClustersProcessor.OpenHistoryClustersDelegate; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.ProfileManager; @@ -57,28 +56,28 @@ public BraveAutocompleteMediator(@NonNull Context context, } @Override - public void onTextChanged(String textWithoutAutocomplete, String textWithAutocomplete) { + public void onTextChanged(String textWithoutAutocomplete) { if (ProfileManager.isInitialized() && !UserPrefs.get(Profile.getLastUsedRegularProfile()) .getBoolean(AUTOCOMPLETE_ENABLED)) { return; } - super.onTextChanged(textWithoutAutocomplete, textWithAutocomplete); + super.onTextChanged(textWithoutAutocomplete); } @Override - public void onUrlFocusChange(boolean hasFocus) { + public void onOmniboxSessionStateChange(boolean activated) { if (!mNativeInitialized) return; - super.onUrlFocusChange(hasFocus); + super.onOmniboxSessionStateChange(activated); } @Override public void removeBraveSearchSuggestion() { if (mDropdownViewInfoListManager instanceof BraveDropdownItemViewInfoListManager) { ((BraveDropdownItemViewInfoListManager) mDropdownViewInfoListManager) - .removeSuggestionsForGroup(BraveSearchBannerProcessor.BRAVE_SEARCH_PROMO_GROUP); + .removeBraveSearchSuggestion(); } } } diff --git a/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediatorBase.java b/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediatorBase.java index d7d75c72649b..7eb171983738 100644 --- a/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediatorBase.java +++ b/android/java/org/chromium/chrome/browser/omnibox/suggestions/BraveAutocompleteMediatorBase.java @@ -17,10 +17,12 @@ class BraveAutocompleteMediatorBase { void loadUrlForOmniboxMatch(int matchIndex, @NonNull AutocompleteMatch suggestion, - @NonNull GURL url, long inputStart, boolean inVisibleSuggestionList) { + @NonNull GURL url, long inputStart, boolean inVisibleSuggestionList, + boolean openInNewTab) { BraveReflectionUtil.InvokeMethod(AutocompleteMediator.class, this, "loadUrlForOmniboxMatch", int.class, matchIndex, AutocompleteMatch.class, suggestion, GURL.class, url, - long.class, inputStart, boolean.class, inVisibleSuggestionList); + long.class, inputStart, boolean.class, inVisibleSuggestionList, boolean.class, + openInNewTab); if (suggestion.getType() == OmniboxSuggestionType.SEARCH_WHAT_YOU_TYPED || suggestion.getType() == OmniboxSuggestionType.SEARCH_SUGGEST) { Context context = (Context) BraveReflectionUtil.getField( diff --git a/android/java/org/chromium/chrome/browser/toolbar/BraveToolbarManager.java b/android/java/org/chromium/chrome/browser/toolbar/BraveToolbarManager.java index 8478daacf0ea..a5fa3116fc80 100644 --- a/android/java/org/chromium/chrome/browser/toolbar/BraveToolbarManager.java +++ b/android/java/org/chromium/chrome/browser/toolbar/BraveToolbarManager.java @@ -50,7 +50,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.tab_management.TabGroupUi; import org.chromium.chrome.browser.tasks.tab_management.TabManagementDelegateProvider; -import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities; import org.chromium.chrome.browser.theme.TopUiThemeColorProvider; import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator; import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarConfiguration; @@ -211,16 +210,13 @@ public void enableBottomControls() { (ViewStub) mActivity.findViewById(R.id.bottom_controls_stub); mBottomControls = (BraveScrollingBottomViewResourceFrameLayout) bottomControlsStub.inflate(); - if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled(mActivity)) { - mTabGroupUi = TabManagementDelegateProvider.getDelegate().createTabGroupUi( - mActivity, mBottomControls.findViewById(R.id.bottom_container_slot), - mBrowserControlsSizer, mIncognitoStateProvider, mScrimCoordinator, - mOmniboxFocusStateSupplier, mBottomSheetController, - mActivityLifecycleDispatcher, mIsWarmOnResumeSupplier, mTabModelSelector, - mTabContentManager, mCompositorViewHolder, - mCompositorViewHolder::getDynamicResourceLoader, mTabCreatorManager, - mLayoutStateProviderSupplier, mSnackbarManager); - } + mTabGroupUi = TabManagementDelegateProvider.getDelegate().createTabGroupUi(mActivity, + mBottomControls.findViewById(R.id.bottom_container_slot), mBrowserControlsSizer, + mIncognitoStateProvider, mScrimCoordinator, mOmniboxFocusStateSupplier, + mBottomSheetController, mActivityLifecycleDispatcher, mIsWarmOnResumeSupplier, + mTabModelSelector, mTabContentManager, mCompositorViewHolder, + mCompositorViewHolder::getDynamicResourceLoader, mTabCreatorManager, + mLayoutStateProviderSupplier, mSnackbarManager); mBottomControlsCoordinatorSupplier.set(new BraveBottomControlsCoordinator( mLayoutStateProviderSupplier, BottomTabSwitcherActionMenuCoordinator.createOnLongClickListener( diff --git a/android/java/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java b/android/java/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java index 7ed654ea78e3..1415e480cd33 100644 --- a/android/java/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java +++ b/android/java/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java @@ -36,7 +36,6 @@ import org.chromium.chrome.browser.omnibox.OmniboxFocusReason; import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; import org.chromium.chrome.browser.tasks.ReturnToChromeUtil; -import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities; import org.chromium.chrome.browser.theme.ThemeColorProvider; import org.chromium.chrome.browser.toolbar.HomeButton; import org.chromium.chrome.browser.toolbar.LocationBarModel; @@ -277,15 +276,7 @@ public void onStartedHiding(@LayoutType int layoutType) { */ void setBottomToolbarVisible(boolean isVisible) { if (mTabSwitcherModeCoordinator != null) { - try { - ChromeActivity activity = BraveActivity.getBraveActivity(); - mTabSwitcherModeCoordinator.showToolbarOnTop( - !isVisible, TabUiFeatureUtilities.isGridTabSwitcherEnabled(activity)); - } catch (BraveActivity.BraveActivityNotFoundException e) { - Log.e(TAG, "setBottomToolbarVisible " + e); - mTabSwitcherModeCoordinator.showToolbarOnTop( - !isVisible, TabUiFeatureUtilities.isGridTabSwitcherEnabled(mContext)); - } + mTabSwitcherModeCoordinator.showToolbarOnTop(!isVisible, true); } mBrowsingModeCoordinator.onVisibilityChanged(isVisible); } diff --git a/android/java/org/chromium/chrome/browser/toolbar/top/BraveTabSwitcherModeTTCoordinator.java b/android/java/org/chromium/chrome/browser/toolbar/top/BraveTabSwitcherModeTTCoordinator.java index 67fae4b64315..bde06ea2e44e 100644 --- a/android/java/org/chromium/chrome/browser/toolbar/top/BraveTabSwitcherModeTTCoordinator.java +++ b/android/java/org/chromium/chrome/browser/toolbar/top/BraveTabSwitcherModeTTCoordinator.java @@ -18,12 +18,10 @@ class BraveTabSwitcherModeTTCoordinator extends TabSwitcherModeTTCoordinator { private MenuButtonCoordinator mBraveMenuButtonCoordinator; BraveTabSwitcherModeTTCoordinator(ViewStub tabSwitcherToolbarStub, - ViewStub tabSwitcherFullscreenToolbarStub, MenuButtonCoordinator menuButtonCoordinator, - boolean isGridTabSwitcherEnabled, boolean isTabToGtsAnimationEnabled, + MenuButtonCoordinator menuButtonCoordinator, boolean isTabToGtsAnimationEnabled, BooleanSupplier isIncognitoModeEnabledSupplier, ToolbarColorObserverManager toolbarColorObserverManager) { - super(tabSwitcherToolbarStub, tabSwitcherFullscreenToolbarStub, menuButtonCoordinator, - isGridTabSwitcherEnabled, isTabToGtsAnimationEnabled, + super(tabSwitcherToolbarStub, menuButtonCoordinator, isTabToGtsAnimationEnabled, isIncognitoModeEnabledSupplier, toolbarColorObserverManager); mBraveMenuButtonCoordinator = menuButtonCoordinator; diff --git a/android/java/org/chromium/chrome/browser/toolbar/top/BraveTopToolbarCoordinator.java b/android/java/org/chromium/chrome/browser/toolbar/top/BraveTopToolbarCoordinator.java index 114a583a3494..02c77bf94793 100644 --- a/android/java/org/chromium/chrome/browser/toolbar/top/BraveTopToolbarCoordinator.java +++ b/android/java/org/chromium/chrome/browser/toolbar/top/BraveTopToolbarCoordinator.java @@ -47,7 +47,7 @@ public class BraveTopToolbarCoordinator extends TopToolbarCoordinator { private ObservableSupplier mConstraintsProxy; public BraveTopToolbarCoordinator(ToolbarControlContainer controlContainer, - ViewStub toolbarStub, ViewStub fullscreenToolbarStub, ToolbarLayout toolbarLayout, + ViewStub toolbarStub, ToolbarLayout toolbarLayout, ToolbarDataProvider toolbarDataProvider, ToolbarTabController tabController, UserEducationHelper userEducationHelper, List buttonDataProviders, OneshotSupplier layoutStateProviderSupplier, @@ -61,9 +61,8 @@ public BraveTopToolbarCoordinator(ToolbarControlContainer controlContainer, ButtonDataProvider identityDiscController, Callback invalidatorCallback, Supplier identityDiscButtonSupplier, Supplier resourceManagerSupplier, - BooleanSupplier isIncognitoModeEnabledSupplier, boolean isGridTabSwitcherEnabled, - boolean isTabToGtsAnimationEnabled, boolean isStartSurfaceEnabled, - boolean isTabGroupsAndroidContinuationEnabled, HistoryDelegate historyDelegate, + BooleanSupplier isIncognitoModeEnabledSupplier, boolean isTabToGtsAnimationEnabled, + boolean isStartSurfaceEnabled, HistoryDelegate historyDelegate, BooleanSupplier partnerHomepageEnabledSupplier, OfflineDownloader offlineDownloader, boolean initializeWithIncognitoColors, Callback startSurfaceLogoClickedCallback, @@ -72,19 +71,18 @@ public BraveTopToolbarCoordinator(ToolbarControlContainer controlContainer, BrowserStateBrowserControlsVisibilityDelegate browserStateBrowserControlsVisibilityDelegate, boolean shouldCreateLogoInStartToolbar, FullscreenManager fullscreenManager) { - super(controlContainer, toolbarStub, fullscreenToolbarStub, toolbarLayout, - toolbarDataProvider, tabController, userEducationHelper, buttonDataProviders, - layoutStateProviderSupplier, normalThemeColorProvider, overviewThemeColorProvider, + super(controlContainer, toolbarStub, toolbarLayout, toolbarDataProvider, tabController, + userEducationHelper, buttonDataProviders, layoutStateProviderSupplier, + normalThemeColorProvider, overviewThemeColorProvider, browsingModeMenuButtonCoordinator, overviewModeMenuButtonCoordinator, appMenuButtonHelperSupplier, tabModelSelectorSupplier, homepageEnabledSupplier, identityDiscController, invalidatorCallback, identityDiscButtonSupplier, - resourceManagerSupplier, isIncognitoModeEnabledSupplier, isGridTabSwitcherEnabled, - isTabToGtsAnimationEnabled, isStartSurfaceEnabled, - isTabGroupsAndroidContinuationEnabled, historyDelegate, - partnerHomepageEnabledSupplier, offlineDownloader, initializeWithIncognitoColors, - startSurfaceLogoClickedCallback, isStartSurfaceRefactorEnabled, constraintsSupplier, - compositorInMotionSupplier, browserStateBrowserControlsVisibilityDelegate, - shouldCreateLogoInStartToolbar, fullscreenManager); + resourceManagerSupplier, isIncognitoModeEnabledSupplier, isTabToGtsAnimationEnabled, + isStartSurfaceEnabled, historyDelegate, partnerHomepageEnabledSupplier, + offlineDownloader, initializeWithIncognitoColors, startSurfaceLogoClickedCallback, + isStartSurfaceRefactorEnabled, constraintsSupplier, compositorInMotionSupplier, + browserStateBrowserControlsVisibilityDelegate, shouldCreateLogoInStartToolbar, + fullscreenManager); mBraveToolbarLayout = toolbarLayout; mBraveMenuButtonCoordinator = browsingModeMenuButtonCoordinator; @@ -94,8 +92,7 @@ public BraveTopToolbarCoordinator(ToolbarControlContainer controlContainer, if (!isStartSurfaceEnabled) { mTabSwitcherModeCoordinator = new BraveTabSwitcherModeTTCoordinator( controlContainer.getRootView().findViewById(R.id.tab_switcher_toolbar_stub), - fullscreenToolbarStub, overviewModeMenuButtonCoordinator, - isGridTabSwitcherEnabled, isTabToGtsAnimationEnabled, + overviewModeMenuButtonCoordinator, isTabToGtsAnimationEnabled, isIncognitoModeEnabledSupplier, mToolbarColorObserverManager); } } diff --git a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java index dc6664a2c353..78c162d7b131 100644 --- a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java +++ b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java @@ -69,12 +69,9 @@ import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider; import org.chromium.chrome.browser.omnibox.status.PageInfoIPHController; import org.chromium.chrome.browser.omnibox.status.StatusCoordinator.PageInfoAction; -import org.chromium.chrome.browser.omnibox.styles.OmniboxImageSupplier; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteControllerProvider; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteDelegate; import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestionsDropdownScrollListener; -import org.chromium.chrome.browser.omnibox.suggestions.SuggestionHost; -import org.chromium.chrome.browser.omnibox.suggestions.UrlBarDelegate; import org.chromium.chrome.browser.omnibox.suggestions.basic.BasicSuggestionProcessor.BookmarkState; import org.chromium.chrome.browser.omnibox.suggestions.history_clusters.HistoryClustersProcessor.OpenHistoryClustersDelegate; import org.chromium.chrome.browser.profiles.Profile; @@ -148,6 +145,7 @@ import java.lang.reflect.Method; import java.util.List; import java.util.function.BooleanSupplier; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -173,8 +171,6 @@ public void testClassesExist() throws Exception { Assert.assertTrue(classExists("org/chromium/chrome/browser/feed/BraveFeedSurfaceMediator")); Assert.assertTrue(classExists("org/chromium/chrome/browser/ntp/NewTabPage")); Assert.assertTrue(classExists("org/chromium/chrome/browser/ntp/BraveNewTabPage")); - Assert.assertTrue(classExists( - "org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor")); Assert.assertTrue( classExists("org/chromium/chrome/browser/sync/settings/ManageSyncSettings")); Assert.assertTrue(classExists( @@ -538,10 +534,10 @@ public void testMethodsForInvocationExist() throws Exception { "org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinator", "createViewProvider", true, ViewProvider.class, Context.class, MVCListAdapter.ModelList.class)); - Assert.assertTrue( - methodExists("org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator", - "loadUrlForOmniboxMatch", true, void.class, int.class, - AutocompleteMatch.class, GURL.class, long.class, boolean.class)); + Assert.assertTrue(methodExists( + "org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator", + "loadUrlForOmniboxMatch", true, void.class, int.class, AutocompleteMatch.class, + GURL.class, long.class, boolean.class, boolean.class)); // Check for method type declaration changes here Assert.assertTrue(methodExists( @@ -678,25 +674,20 @@ public void testConstructorsExistAndMatch() throws Exception { NewTabPageUma.class, boolean.class, NativePageHost.class, Tab.class, String.class, BottomSheetController.class, Supplier.class, WindowAndroid.class, Supplier.class, SettingsLauncher.class, HomeSurfaceTracker.class, ObservableSupplier.class)); - Assert.assertTrue(constructorsMatch( - "org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor", - "org/chromium/chrome/browser/omnibox/suggestions/editurl/BraveEditUrlSuggestionProcessor", - Context.class, SuggestionHost.class, UrlBarDelegate.class, - OmniboxImageSupplier.class, Supplier.class, Supplier.class)); Assert.assertTrue(constructorsMatch( "org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator", "org/chromium/chrome/browser/toolbar/top/BraveTopToolbarCoordinator", - ToolbarControlContainer.class, ViewStub.class, ViewStub.class, ToolbarLayout.class, + ToolbarControlContainer.class, ViewStub.class, ToolbarLayout.class, ToolbarDataProvider.class, ToolbarTabController.class, UserEducationHelper.class, List.class, OneshotSupplier.class, ThemeColorProvider.class, ThemeColorProvider.class, MenuButtonCoordinator.class, MenuButtonCoordinator.class, ObservableSupplier.class, ObservableSupplier.class, ObservableSupplier.class, ButtonDataProvider.class, Callback.class, Supplier.class, Supplier.class, - BooleanSupplier.class, boolean.class, boolean.class, boolean.class, boolean.class, - HistoryDelegate.class, BooleanSupplier.class, OfflineDownloader.class, - boolean.class, Callback.class, boolean.class, ObservableSupplier.class, - ObservableSupplier.class, BrowserStateBrowserControlsVisibilityDelegate.class, - boolean.class, FullscreenManager.class)); + BooleanSupplier.class, boolean.class, boolean.class, HistoryDelegate.class, + BooleanSupplier.class, OfflineDownloader.class, boolean.class, Callback.class, + boolean.class, ObservableSupplier.class, ObservableSupplier.class, + BrowserStateBrowserControlsVisibilityDelegate.class, boolean.class, + FullscreenManager.class)); Assert.assertTrue(constructorsMatch( "org/chromium/chrome/browser/toolbar/menu_button/MenuButtonCoordinator", "org/chromium/chrome/browser/toolbar/menu_button/BraveMenuButtonCoordinator", @@ -769,7 +760,7 @@ public void testConstructorsExistAndMatch() throws Exception { BooleanSupplier.class, Supplier.class, OmniboxActionDelegate.class, BrowserStateBrowserControlsVisibilityDelegate.class, Callback.class, BackPressManager.class, OmniboxSuggestionsDropdownScrollListener.class, - OpenHistoryClustersDelegate.class)); + OpenHistoryClustersDelegate.class, ObservableSupplier.class)); Assert.assertTrue(constructorsMatch( "org/chromium/chrome/browser/omnibox/LocationBarMediator", "org/chromium/chrome/browser/omnibox/BraveLocationBarMediator", Context.class, @@ -781,7 +772,8 @@ public void testConstructorsExistAndMatch() throws Exception { BraveLocationBarMediator.getLensControllerClass(), BraveLocationBarMediator.getSaveOfflineButtonStateClass(), BraveLocationBarMediator.getOmniboxUmaClass(), BooleanSupplier.class, - BraveLocationBarMediator.getOmniboxSuggestionsDropdownEmbedderImplClass())); + BraveLocationBarMediator.getOmniboxSuggestionsDropdownEmbedderImplClass(), + ObservableSupplier.class)); Assert.assertTrue(constructorsMatch("org/chromium/chrome/browser/IntentHandler", "org/chromium/chrome/browser/BraveIntentHandler", Activity.class, IntentHandler.IntentHandlerDelegate.class)); @@ -829,7 +821,7 @@ public void testConstructorsExistAndMatch() throws Exception { Context.class, SelectableListLayout.class, SelectionDelegate.class, SearchDelegate.class, DragReorderableRecyclerViewAdapter.class, boolean.class, OneshotSupplier.class, BookmarkModel.class, BookmarkOpener.class, - BookmarkUiPrefs.class, ModalDialogManager.class)); + BookmarkUiPrefs.class, ModalDialogManager.class, Runnable.class)); Assert.assertTrue(constructorsMatch( "org/chromium/chrome/browser/bookmarks/BookmarkManagerCoordinator", "org/chromium/chrome/browser/bookmarks/BraveBookmarkManagerCoordinator", @@ -844,7 +836,7 @@ public void testConstructorsExistAndMatch() throws Exception { boolean.class, boolean.class, ObservableSupplierImpl.class, Profile.class, BookmarkUndoController.class, ModelList.class, BookmarkUiPrefs.class, Runnable.class, BookmarkImageFetcher.class, ShoppingService.class, - SnackbarManager.class)); + SnackbarManager.class, Consumer.class)); Assert.assertTrue(constructorsMatch("org/chromium/chrome/browser/bookmarks/BookmarkBridge", "org/chromium/chrome/browser/bookmarks/BraveBookmarkBridge", long.class)); Assert.assertTrue(constructorsMatch("org/chromium/chrome/browser/bookmarks/BookmarkModel", @@ -892,9 +884,6 @@ public void testFieldsExist() throws Exception { fieldExists("org/chromium/chrome/browser/ntp/NewTabPage", "mTabModelSelector")); Assert.assertTrue(fieldExists( "org/chromium/chrome/browser/ntp/NewTabPage", "mBottomSheetController")); - Assert.assertTrue(fieldExists( - "org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor", - "mHasClearedOmniboxForFocus")); Assert.assertTrue( fieldExists("org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesMediator", "mTileGroup")); @@ -1057,6 +1046,8 @@ public void testFieldsExist() throws Exception { "org/chromium/chrome/browser/omnibox/LocationBarMediator", "mIsTablet")); Assert.assertTrue(fieldExists("org/chromium/chrome/browser/omnibox/LocationBarMediator", "mIsLocationBarFocusedFromNtpScroll")); + Assert.assertTrue(fieldExists("org/chromium/chrome/browser/omnibox/LocationBarMediator", + "mShouldClearOmniboxOnFocus")); Assert.assertTrue( fieldExists("org/chromium/chrome/browser/omnibox/LocationBarMediator", "mContext")); Assert.assertTrue(fieldExists( diff --git a/app/bookmarks_strings.grdp b/app/bookmarks_strings.grdp index e459f64d1963..e72ce363ff4c 100644 --- a/app/bookmarks_strings.grdp +++ b/app/bookmarks_strings.grdp @@ -201,9 +201,15 @@ Edit bookmark + + Edit + Name + + This page is saved to $1All Bookmarks + Bookmark name diff --git a/app/brave_main_delegate_browsertest.cc b/app/brave_main_delegate_browsertest.cc index 0f578a19ca3d..880bf3446547 100644 --- a/app/brave_main_delegate_browsertest.cc +++ b/app/brave_main_delegate_browsertest.cc @@ -10,9 +10,9 @@ #include "chrome/browser/browser_features.h" #include "chrome/browser/companion/core/features.h" #include "chrome/browser/companion/visual_search/features.h" -#include "chrome/browser/dips/dips_features.h" #include "chrome/browser/domain_reliability/service_factory.h" #include "chrome/browser/enterprise/connectors/analysis/content_analysis_features.h" +#include "chrome/browser/preloading/preloading_features.h" #include "chrome/browser/promos/promos_features.h" #include "chrome/browser/signin/signin_features.h" #include "chrome/common/chrome_features.h" @@ -48,7 +48,9 @@ #include "components/shared_highlighting/core/common/shared_highlighting_features.h" #include "components/signin/public/base/signin_buildflags.h" #include "components/subresource_filter/core/common/common_features.h" +#include "content/common/features.h" #include "content/public/common/content_features.h" +#include "content/public/common/dips_utils.h" #include "content/public/test/browser_test.h" #include "gpu/config/gpu_finch_features.h" #include "media/base/media_switches.h" @@ -63,7 +65,7 @@ #include "chrome/test/base/android/android_browser_test.h" #else #include "chrome/browser/sharing_hub/sharing_hub_features.h" -#include "chrome/browser/ui/profile_picker.h" +#include "chrome/browser/ui/profiles/profile_picker.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/translate/core/common/translate_util.h" @@ -161,8 +163,9 @@ IN_PROC_BROWSER_TEST_F(BraveMainDelegateBrowserTest, DisabledFeatures) { &companion::features::internal::kSidePanelCompanion, &companion::features::internal::kSidePanelCompanion2, &companion::visual_search::features::kVisualSearchSuggestions, + &content::kServiceWorkerAutoPreload, + &content_settings::features::kThirdPartyCookieDeprecationCookieSettings, &content_settings::features::kUserBypassUI, - &dips::kFeature, &enterprise_connectors::kLocalContentAnalysisEnabled, #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) &enterprise_signals::features::kDeviceSignalsConsentDialog, @@ -184,6 +187,7 @@ IN_PROC_BROWSER_TEST_F(BraveMainDelegateBrowserTest, DisabledFeatures) { &features::kDesktopPWAsLinkCapturing, #endif &features::kDigitalGoodsApi, + &features::kDIPS, &features::kExtensionsMenuInAppMenu, &features::kFedCm, &features::kFedCmWithoutThirdPartyCookies, @@ -196,11 +200,14 @@ IN_PROC_BROWSER_TEST_F(BraveMainDelegateBrowserTest, DisabledFeatures) { &features::kNotificationTriggers, &features::kOmniboxTriggerForNoStatePrefetch, &features::kOmniboxTriggerForPrerender2, -#if !BUILDFLAG(IS_ANDROID) + &features::kPerformanceSettingsPreloadingSubpage, &features::kPrivacyGuide3, -#endif #if BUILDFLAG(IS_ANDROID) &features::kPrivacyGuideAndroidPostMVP, +#endif + &features::kPrivacyGuidePreload, +#if BUILDFLAG(IS_ANDROID) + &features::kPrivacyGuidePreloadAndroid, #endif &features::kPrivacySandboxAdsAPIsOverride, &features::kSCTAuditing, @@ -218,6 +225,7 @@ IN_PROC_BROWSER_TEST_F(BraveMainDelegateBrowserTest, DisabledFeatures) { &features::kWebOTP, &history::kOrganicRepeatableQueries, &history::kSyncSegmentsData, + &history_clusters::kRenameJourneys, &history_clusters::kSidePanelJourneys, &history_clusters::features::kOnDeviceClustering, &history_clusters::features::kOnDeviceClusteringKeywordFiltering, @@ -243,13 +251,17 @@ IN_PROC_BROWSER_TEST_F(BraveMainDelegateBrowserTest, DisabledFeatures) { &net::features::kEnableWebTransportDraft07, &net::features::kNoncedPartitionedCookies, &net::features::kPartitionedCookies, + &net::features::kThirdPartyPartitionedStorageAllowedByDefault, &network::features::kFledgePst, &network::features::kPrivateStateTokens, &network_time::kNetworkTimeServiceQuerying, + &ntp_features::kCustomizeChromeSidePanelExtensionsCard, + &ntp_features::kCustomizeChromeWallpaperSearch, &ntp_features::kNtpAlphaBackgroundCollections, &ntp_features::kNtpBackgroundImageErrorDetection, &ntp_features::kNtpChromeCartModule, &ntp_features::kNtpHistoryClustersModule, + &ntp_features::kNtpHistoryClustersModuleDiscounts, &ntp_features::kNtpHistoryClustersModuleLoad, &omnibox::kInspireMe, &omnibox::kDocumentProviderNoSetting, @@ -259,11 +271,12 @@ IN_PROC_BROWSER_TEST_F(BraveMainDelegateBrowserTest, DisabledFeatures) { &omnibox::kOmniboxMostVisitedTilesOnSrp, &omnibox::kOmniboxSteadyStateHeight, &omnibox::kRichAutocompletion, + &optimization_guide::features::kOptimizationGuideFetchingForSRP, &optimization_guide::features::kOptimizationHints, &optimization_guide::features::kRemoteOptimizationGuideFetching, &optimization_guide::features:: kRemoteOptimizationGuideFetchingAnonymousDataConsent, - &optimization_guide::features::kOptimizationGuideFetchingForSRP, + &optimization_guide::features::kTextEmbeddingPageContentAnnotations, &page_image_service::kImageService, &page_image_service::kImageServiceSuggestPoweredImages, #if !BUILDFLAG(IS_ANDROID) @@ -279,8 +292,12 @@ IN_PROC_BROWSER_TEST_F(BraveMainDelegateBrowserTest, DisabledFeatures) { &promos_features::kIOSPromoPasswordBubble, &safe_browsing::kExtensionTelemetry, &safe_browsing::kExtensionTelemetryDeclarativeNetRequestSignal, + &safe_browsing::kExtensionTelemetryDisableOffstoreExtensions, + &safe_browsing::kExtensionTelemetryTabsApiSignal, + &segmentation_platform::features::kSegmentationPlatformCollectTabRankData, &segmentation_platform::features::kSegmentationPlatformDeviceTier, &segmentation_platform::features::kSegmentationPlatformFeature, + &segmentation_platform::features::kSegmentationPlatformTimeDelaySampling, &send_tab_to_self::kSendTabToSelfSigninPromo, &shared_highlighting::kIOSSharedHighlightingV2, &shared_highlighting::kSharedHighlightingManager, diff --git a/app/brave_strings.grd b/app/brave_strings.grd index bd0c95b0b8b4..f4d0355dfa8c 100644 --- a/app/brave_strings.grd +++ b/app/brave_strings.grd @@ -7,181 +7,181 @@ If you update this file, be sure also to update google_chrome_strings.grd. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -683,8 +683,8 @@ Permissions you've already given to websites and apps may apply to this account. Brave recommends scanning this file because it may be dangerous - - Brave blocks some downloads + + Learn why Brave blocks some downloads @@ -1439,18 +1439,20 @@ Permissions you've already given to websites and apps may apply to this account. Share a Brave tab - - Brave was automatically closed - - - Your organization closes Brave when it isn't used for $130 minutes. Browsing data was deleted. This could include history, autofill, and downloads. - - - Your organization deletes Brave data when it isn't used for $130 minutes. This could include history, autofill, and downloads. - - - Your organization closes Brave when it isn't used for $130 minutes. - + + + Brave was automatically closed + + + Your organization closes Brave when it isn't used for $130 minutes. Browsing data was deleted. This could include history, autofill, and downloads. + + + Your organization deletes Brave data when it isn't used for $130 minutes. This could include history, autofill, and downloads. + + + Your organization closes Brave when it isn't used for $130 minutes. + + diff --git a/app/brave_strings_override.grd b/app/brave_strings_override.grd index 585f080b2b10..9636e8063965 100644 --- a/app/brave_strings_override.grd +++ b/app/brave_strings_override.grd @@ -359,6 +359,8 @@ Permissions you've already given to websites and apps may apply to this account. + + diff --git a/app/extensions_strings.grdp b/app/extensions_strings.grdp index 3e702a76b820..2a53a2e49aae 100644 --- a/app/extensions_strings.grdp +++ b/app/extensions_strings.grdp @@ -26,6 +26,15 @@ Collect errors + + This extension cannot read and change site information or run in the background + + + This extension may run in the background + + + This extension may read and change site information or run in the background + Nothing to see here, move along. @@ -302,6 +311,9 @@ This extension requires no special permissions and has no additional site access + + Pin to toolbar + Remove extension @@ -593,6 +605,12 @@ Include Ctrl, Alt, or Search + + {FILE_COUNT, plural, + =1 {Open and edit {FILE1}1.txt in this extension} + other {Open and edit {FILE1}1.txt, ... in this app} + } + diff --git a/app/generated_resources.grd b/app/generated_resources.grd index 58d719b341cd..fa82645ede10 100644 --- a/app/generated_resources.grd +++ b/app/generated_resources.grd @@ -758,7 +758,7 @@ are declared in tools/grit/grit_rule.gni. Just once - Convert image to text + Extract text from PDF Always @@ -1048,7 +1048,7 @@ are declared in tools/grit/grit_rule.gni. Just Once - Convert image to text + Extract Text From PDF Always @@ -2765,9 +2765,6 @@ are declared in tools/grit/grit_rule.gni. This file can't be verified because Safe Browsing is off - - Learn why $1Brave blocks some downloads - $1Turn on Safe Browsing to make downloading files safer @@ -2813,12 +2810,6 @@ are declared in tools/grit/grit_rule.gni. Your organization blocked this file because it is too big for a security check. You can open files up to 50 MB. - - This file might be a virus or malware.$1You can send it to Google Safe Browsing to check if it's unsafe. Scans usually take a few seconds. - - - Learn more about malware scans - This file might be a virus or malware @@ -2837,15 +2828,6 @@ are declared in tools/grit/grit_rule.gni. Try again - - Scan before opening - - - Scan for malware - - - Scanning... - Checking with your organization's security policies... @@ -2963,6 +2945,44 @@ are declared in tools/grit/grit_rule.gni. This file may hide malware + + + Scan before opening + + + Scan for malware + + + Scanning... + + + This file might be a virus or malware.$1You can send it to Google Safe Browsing to check if it's unsafe. Scans usually take a few seconds. + + + This encrypted file might be a virus or malware.$1To check if it's unsafe, you can send the file and password to Google Safe Browsing. Scans usually take a few seconds.$1To scan, add the file's password. + + + Learn more about malware scans + + + File password + + + Enter the file's password + + + Incorrect password. Try again. + + + File password + + + Enter the file's password + + + Incorrect password. Try again. + + @@ -5089,6 +5109,9 @@ are declared in tools/grit/grit_rule.gni. Read attached devices information and data + + Read Bluetooth peripherals information and data + Run ChromeOS Flex diagnostic tests @@ -5109,6 +5132,9 @@ are declared in tools/grit/grit_rule.gni. Read attached devices information and data + + Read Bluetooth peripherals information and data + Run ChromeOS diagnostic tests @@ -5392,6 +5418,15 @@ are declared in tools/grit/grit_rule.gni. Pinned by your administrator + + Pin $1Gmail Checker + + + Unpin $1Gmail Checker + + + $1Gmail Checker is pinned by your administrator + Manage extension @@ -5478,6 +5513,15 @@ are declared in tools/grit/grit_rule.gni. Pinned by your Administrator + + Pin $1Gmail Checker + + + Unpin $1Gmail Checker + + + $1Gmail Checker is pinned by your Administrator + Manage Extension @@ -5863,10 +5907,10 @@ Keep your key file in a safe place. You will need it to create new versions of y Extensions - more options + More options - Select to see more options for $1MyExtension + More options for $1MyExtension Pin extension @@ -6478,23 +6522,6 @@ Keep your key file in a safe place. You will need it to create new versions of y In Brave Password Manager for $1user@gmail.com - - - To Brave Password Manager $1user@gmail.com - - - In Brave Password Manager $1user@gmail.com - - - To your Brave sync chain, $1user@gmail.com - - - In your Brave sync chain, $1user@gmail.com - - - Only on this device - - Sign In @@ -6511,11 +6538,9 @@ Keep your key file in a safe place. You will need it to create new versions of y Manage passwords - - - App ($1com.netflix.mediaclient) - - + + App ($1com.netflix.mediaclient) + Got it @@ -6966,11 +6991,6 @@ Keep your key file in a safe place. You will need it to create new versions of y Clear input - - - Search or type web address - - Why this suggestion? @@ -7166,6 +7186,9 @@ Keep your key file in a safe place. You will need it to create new versions of y Uploaded image + + Your uploaded image + Upload from device @@ -7211,6 +7234,9 @@ Keep your key file in a safe place. You will need it to create new versions of y Custom color + + Color picker + Theme is set by your Organization @@ -7468,6 +7494,9 @@ Keep your key file in a safe place. You will need it to create new versions of y Google Drive files + + Drive + Drive files @@ -10070,6 +10099,14 @@ Check your passwords anytime in $1Brave P Stop sharing + + + Stop + + + You're sharing your screen + + @@ -10199,14 +10236,14 @@ Check your passwords anytime in $1Brave P - + ARC Platform - + + + Choose a passkey for $1example.com + + + On this device + + + From "$1Pixel 7" + + + On other devices + + + From your Brave profile + + + From iCloud Keychain + + + From "$1Dashlane" + + + From Windows Hello + + + From "$1Pixel 7" + @@ -14988,6 +15082,13 @@ Please help our engineers fix this problem. Tell us what happened right before y Enabled – $1tabs shrink to pinned tab width + + + Tab Groups Save and Sync + + + Enables saving and recalling of tab groups. Right click a tab group to save it. Recall groups from the bookmarks bar. + Brave Refresh 2023 @@ -15095,6 +15196,12 @@ Please help our engineers fix this problem. Tell us what happened right before y You can use your $1idp.example account on this site. To continue, sign in to $1idp.example. + + Cannot continue with $1idp.example. + + + Something went wrong. + Sign in to $1rp.example @@ -15436,11 +15543,23 @@ Please help our engineers fix this problem. Tell us what happened right before y labore - Button + Lorem ipsum Lorem ipsum dolor sit amet + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. + + + <b>Nisi ut aliquip ex ea commodo consequat. Duis aute irure dolorin reprehenderit in voluptate</b> velit esse cillum dolore eufugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,sunt in culpa qui officia deserunt mollit anim id est laborum. + + + Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque. + + + Lorem ipsum + diff --git a/app/generated_resources_override.grd b/app/generated_resources_override.grd index 451c7a6ea4c9..8f5235d403d2 100644 --- a/app/generated_resources_override.grd +++ b/app/generated_resources_override.grd @@ -566,14 +566,10 @@ are declared in tools/grit/grit_rule.gni. - - - - @@ -603,8 +599,6 @@ are declared in tools/grit/grit_rule.gni. - - @@ -806,6 +800,9 @@ are declared in tools/grit/grit_rule.gni. + + + @@ -828,7 +825,7 @@ are declared in tools/grit/grit_rule.gni. - + Not from Web Store. @@ -1139,6 +1136,8 @@ are declared in tools/grit/grit_rule.gni. + + Sign-in data will be stored on this device after you exit Private mode. You'll be able to sign in to this website with your device again later. diff --git a/app/os_settings_search_tag_strings.grdp b/app/os_settings_search_tag_strings.grdp index 5e3bc3afc7a8..a1e42c090393 100644 --- a/app/os_settings_search_tag_strings.grdp +++ b/app/os_settings_search_tag_strings.grdp @@ -472,6 +472,9 @@ Show Google Drive suggestions + + Local Data Recovery + @@ -746,6 +749,9 @@ Overscan + + Battery Saver + diff --git a/app/os_settings_strings.grdp b/app/os_settings_strings.grdp index 7e410a649814..c228fd5d924a 100644 --- a/app/os_settings_strings.grdp +++ b/app/os_settings_strings.grdp @@ -912,6 +912,9 @@ Preferred search engine + + Set search engine in Brave browser settings + Set your default search engine for Brave browser and $1Chromebook Launcher @@ -924,10 +927,10 @@ Disabled - + On - + Off @@ -974,7 +977,7 @@ Clean up offline storage? - This will remove $15.0 GB of space used by your offline files. Some files will still be available offline. <a target="_blank" href="$2https://google.com/">Learn more</a> + This will remove up to $15.0 GB of space used by your offline files. Some files will still be available offline. <a target="_blank" href="$2https://google.com/">Learn more</a> Can’t clean up storage while file sync is on @@ -1057,6 +1060,9 @@ Not signed in + + Allow syncing on metered networks + File sync on @@ -1078,6 +1084,9 @@ Network file shares + + Access shared files, folders, or drives on a local network. <a>Learn more</a> + Set up or manage network file shares. <a>Learn more</a> @@ -1114,39 +1123,39 @@ Share mounted successfully. - - + + OneDrive - + Signed in as <strong>$1john@google.com</strong> - - Disconnected + + Add your Microsoft account - - Connect account + + Add - - Disconnect + + Remove - + Open OneDrive folder - + Microsoft 365 - + Open Word, Excel, and PowerPoint files - + Microsoft 365 files - - Ask before moving Microsoft files to Google Drive + + Ask before copying or moving Microsoft files to Google Drive - - Ask before moving Microsoft files to OneDrive + + Ask before copying or moving Microsoft files to Microsoft OneDrive @@ -2297,6 +2306,9 @@ Press an assigned switch or key to remove assignment. Manage USB devices + + Let Android apps access USB devices on this Chromebook + Only supported devices are shown. @@ -2614,19 +2626,19 @@ Press an assigned switch or key to remove assignment. - + Managed Development Environment ($1HappyVm) - + Give $1HappyVm permission to access USB devices. $1HappyVm won't remember a USB device after it's removed. - + Shared folders are available in $1HappyVm at $2/mnt/chromeos. - + To share, right-click on a folder in Files app, then select "Share with $1HappyVm". - + Couldn't unshare because an application is using this folder. The folder will be unshared when $1HappyVm is next shut down. @@ -2646,21 +2658,33 @@ Press an assigned switch or key to remove assignment. Google Play Store + + Manage Google Play preferences + Turn on Google Play Store Manage Android preferences + + Android Settings + Remove Google Play Store + + Remove Google Play and Android apps + Remove Remove Android apps? + + Remove Google Play and Android apps? + Remove Android apps @@ -2670,6 +2694,9 @@ Press an assigned switch or key to remove assignment. Let Android apps access USB devices on this Chromebook. Permission will be requested each time you plug in a USB device. Individual Android apps will ask for additional permissions. + + Open Google Play + @@ -2722,6 +2749,24 @@ Press an assigned switch or key to remove assignment. Customize mouse buttons + + Key combination + + + None + + + Change button name + + + Cancel + + + Save + + + New button name + @@ -3075,9 +3120,6 @@ Press an assigned switch or key to remove assignment. Touchpad speed - - Touchpad scroll speed - Slow @@ -3090,16 +3132,14 @@ Press an assigned switch or key to remove assignment. TrackPoint speed - - + Scrolling speed - - - Mouse cursor + + Cursor - - Mouse scrolling + + Scrolling Swap primary mouse button @@ -3134,15 +3174,14 @@ Press an assigned switch or key to remove assignment. Faster movements with your mouse will move the cursor farther - - - Enable scroll acceleration. <a>Learn more</a> + + Scroll acceleration <a>Learn more</a> - + Cursor speed - - Enable cursor acceleration + + Cursor acceleration Enable TrackPoint acceleration @@ -3156,9 +3195,6 @@ Press an assigned switch or key to remove assignment. Faster movements on your touchpad will move the cursor farther - - Enable touchpad scroll acceleration - Mouse and touchpad @@ -3184,7 +3220,7 @@ Press an assigned switch or key to remove assignment. Use touchpad and keyboard to right-click - disabled + Disabled search + click @@ -3195,89 +3231,88 @@ Press an assigned switch or key to remove assignment. alt + click - Select an action for each key Select a shortcut for each action - + insert - + home - + end - + page up - + page down - + delete - + alt + backspace - + search + backspace launcher + backspace - + ctrl + alt + up arrow - + search + left arrow launcher + left arrow - + ctrl + alt + down arrow - + search + right arrow launcher + right arrow - + search + shift + backspace launcher + shift + backspace - + alt + down arrow - + search + down arrow launcher + down arrow - + alt + up arrow - + search + up arrow launcher + up arrow - disabled + Disabled - Print and scan + Printers and Scanners Print server @@ -3285,6 +3320,12 @@ Press an assigned switch or key to remove assignment. Printers + + Print + + + View or add printers and see active print jobs + Set up or manage CUPS printers. <a>Learn more</a> @@ -4279,12 +4320,21 @@ Press an assigned switch or key to remove assignment. Enable Guest browsing + + Guest browsing + Show usernames and photos on the sign-in screen Restrict sign-in to the following users: + + Limit who can sign in + + + You can limit sign-in to certain users. This removes the "Add profile" option on the sign-in screen. You can also remove current users. + $1John Smith (owner) @@ -4657,15 +4707,33 @@ Press an assigned switch or key to remove assignment. Unlock your $1Chromebook with your phone. <a target="_blank" href="$2https://google.com/">Learn more</a> + + Change password + + + Device password + + + Brave sync chain password + Lock screen from sleep mode Remove + + Password + + + Device password or Brave sync chain password + PIN + + Set up + Set up @@ -4883,12 +4951,18 @@ Press an assigned switch or key to remove assignment. While charging + + While inactive and plugged in + Idle action while charging While on battery + + While inactive and on battery + Idle action while on battery @@ -4931,17 +5005,20 @@ Press an assigned switch or key to remove assignment. $156% - + Battery Saver - - Enable Energy saver to extend battery life by turning off background functions such as[...] + + Extends battery life by reducing brightness, limiting background activity and visual effects, delaying notifications, and turning on Brave Energy Saver. Reset settings + + Reset + Powerwash @@ -4951,6 +5028,9 @@ Press an assigned switch or key to remove assignment. Remove all user accounts and reset your $1Brave device to be just like new. + + Remove all user accounts and reset your Chromebook to be just like new. + A restart is required before your device can be reset with Powerwash. <a>Learn more</a> @@ -5120,9 +5200,15 @@ Press an assigned switch or key to remove assignment. Refresh Rate + + Refresh rate + Determines the frequency that the screen updates + + With a higher refresh rate, you'll have a smoother display with more details. Increased refresh rate may impact battery life. + $160 Hz @@ -5132,9 +5218,15 @@ Press an assigned switch or key to remove assignment. Display size + + Display and text size + Make items on your screen smaller or larger + + Make items on your screen, including text, smaller or larger + $1120% @@ -5177,9 +5269,15 @@ Press an assigned switch or key to remove assignment. Overscan + + Display boundaries + Adjust the boundaries of your display + + Press the arrow keys to shrink or expand the display area. To move the display area around, press shift and +, then use the arrow keys. + Tap the following keys to adjust or move the cropping area @@ -5274,6 +5372,9 @@ Press an assigned switch or key to remove assignment. Use your IP address to determine location (default) + + Use your IP address to determine location + Use only Wi-Fi to determine location @@ -5379,7 +5480,22 @@ Press an assigned switch or key to remove assignment. launcher - disabled + Disabled + + + $1Internal Keyboard has been connected + + + $1Internal Keyboard has been disconnected + + + All mice have been disconnected + + + All touchpads have been disconnected + + + All TrackPoints have been disconnected @@ -5458,6 +5574,9 @@ Press an assigned switch or key to remove assignment. Change input settings + + Input settings + Launcher @@ -5488,17 +5607,38 @@ Press & hold keyboard keys to see accent marks and special characters. This Manage your apps + + Allow notifications + + + More Android settings and permissions + + + More web app settings and permissions + + + More Brave app settings and permissions + + + Open in $1Calculator app + Notifications + + Manage app notifications, Do not disturb, and app badging + $13 apps - + Do not disturb enabled Do not disturb + + + Notifications won't pop up on the screen. You can still see notifications by clicking the Do not disturb icon on the bottom right of your screen. When turned on, all notifications will be silenced @@ -5521,6 +5661,9 @@ Press & hold keyboard keys to see accent marks and special characters. This Install apps and games from Google Play on your $1Chromebook. <a target="_blank" href="$2https://google.com/">Learn more</a> + + You can download Android apps and games through the Play Store. <a target="_blank" href="$1https://google.com/">Learn more</a> + @@ -5530,6 +5673,13 @@ Press & hold keyboard keys to see accent marks and special characters. This <br><br> This doesn’t affect apps or content on other devices. + + Google Play and apps you've downloaded from Google Play will be deleted from this Chromebook. + <br><br> + Content you've purchased through Google Play such as movies, TV shows, music, books, as well as purchases from other apps may also be deleted. + <br><br> + This doesn't affect apps or content on other devices. + App details @@ -5766,6 +5916,12 @@ Press & hold keyboard keys to see accent marks and special characters. This Restore apps on startup + + Restore session on startup + + + After restarting, continue where you left off with apps, websites, and open windows + Always restore @@ -5780,5 +5936,8 @@ Press & hold keyboard keys to see accent marks and special characters. This System Preferences + + Storage and power + diff --git a/app/os_settings_strings_override.grdp b/app/os_settings_strings_override.grdp index 81565add4f35..a52d6d203981 100644 --- a/app/os_settings_strings_override.grdp +++ b/app/os_settings_strings_override.grdp @@ -13,6 +13,9 @@ Find more accessibility tools in the Web Store + + You can limit sign-in to certain users. This removes the "Add profile" option on the sign-in screen. You can also remove current users. + diff --git a/app/password_manager_ui_strings.grdp b/app/password_manager_ui_strings.grdp index cf9eace47b42..86ef76ba75dd 100644 --- a/app/password_manager_ui_strings.grdp +++ b/app/password_manager_ui_strings.grdp @@ -73,6 +73,18 @@ When you share a copy of your <b>username</b> and <b>password</b>, your family member can fill them using Brave Password Manager + + <b>$1</b>John Doe can now use your username and password when they use Brave Password Manager to sign in to <b>$2</b>website.com. <a href="$3" target="_blank">Learn more</a> + + + Your family members can now use your username and password when they use Brave Password Manager to sign in to <b>$1</b>website.com. <a href="$2" target="_blank">Learn more</a> + + + To stop others from using your password, change it on <a href="$1" target="_blank">$2</a>website.com + + + To stop others from using your password, open the app to change your password + Manage family @@ -571,7 +583,7 @@ Get here quicker - Add a shortcut to $1Brave Password Manager + Add a shortcut to Brave Password Manager Use saved passwords on any device @@ -582,6 +594,9 @@ Show passwords from your Brave sync chain + + Show passwords and passkeys from your Brave sync chain + Delete password? @@ -615,7 +630,18 @@ Move - + + + Manage passkeys in your Brave profile + + + Use passkeys across your Apple devices + + + When on, passkeys are created in iCloud Keychain and are available across your Apple devices. When off, passkeys are created in your Brave profile on this device. + + + Manage passkeys diff --git a/app/printing_strings.grdp b/app/printing_strings.grdp index 78d61902aa2f..cc76fbb37f76 100644 --- a/app/printing_strings.grdp +++ b/app/printing_strings.grdp @@ -87,6 +87,9 @@ Flip on short edge + + No border + Pages diff --git a/app/settings_brave_strings.grdp b/app/settings_brave_strings.grdp index a88103b788ac..fbfbce9eb7b1 100644 --- a/app/settings_brave_strings.grdp +++ b/app/settings_brave_strings.grdp @@ -115,6 +115,20 @@ + + + Brave preloads pages you're likely to visit, so that they load more quickly when you visit them + + + Brave preloads even more pages that you're likely to visit, so that they load more quickly when you visit them + + + When a site asks to privately preload links on their page, Brave uses Brave servers. This hides your identity from the preloaded site, but Brave learns what sites get preloaded. + + + If you allow cookies, Brave may use them when preloading + + To fix spelling errors, Brave sends the text you type in text fields to Brave @@ -253,6 +267,12 @@ Checks URLs with a list of unsafe sites stored in Brave. If a site tries to steal your password, or when you download a harmful file, Brave may also send URLs, including bits of page content, to Safe Browsing. + + Warns you about dangerous sites, even ones Brave didn't know about before, by analyzing more data from sites than standard protection. You can choose to skip Brave warnings. + + + Learn more about <a href="$1" target="_blank"><a href="$1" target="_blank">how Brave keeps your data private</a></a> + @@ -339,7 +359,11 @@ + Brave regularly checks to make sure your browser has the safest settings. We'll let you know if anything needs your review. + + Brave will let you know if anything needs your review + diff --git a/app/settings_strings.grdp b/app/settings_strings.grdp index 60998ba3cd8d..07f6c9597874 100644 --- a/app/settings_strings.grdp +++ b/app/settings_strings.grdp @@ -56,7 +56,7 @@ Send feedback - Get the most ouf of Brave + Get the most out of Brave This guide helps you understand your choices, so that Brave works the way you want to @@ -118,10 +118,10 @@ Downloading text recognition files - Convert PDF images to text + Extract text from PDF - Scan PDF images to convert content to text for the screen reader, when available. Only supported on Brave browser. + Scan PDF to extract text for the screen reader. Only supported on Brave browser Live Caption @@ -184,6 +184,21 @@ Manage accessibility features + + + Swipe between pages + + + + + Navigate back and forward with swipe gesture + + + + + Turn on to navigate back and forward + + @@ -534,38 +549,41 @@ Delete IBAN - - UPI ID - - - Never - Password Manager Create, save, and manage your passwords so you can easily sign in to sites and apps. - - Passwords + + Saved payment methods will appear here - - Passwords on this device only + + Enter your username - - Passwords on this device and in your Brave sync chain + + Site - - Check passwords + + Edit passkey + + + When you edit your passkey, your $1relyingPartyId account won't change + + + Saved addresses will appear here + + + Warn you if passwords are exposed in a data breach - - Canceled + + Warn you if a password was compromised in a data breach - - Checked passwords + + When you sign in to your Brave sync chain, this feature is turned on. - - Keep your passwords safe from data breaches and other security issues + + Checking passwords ($16 of $231)… {COUNT, plural, @@ -579,12 +597,6 @@ =1 {1 compromised password} other {{NUM_COMPROMISED} compromised passwords}} - - {COUNT, plural, - =0 {No weak passwords found} - =1 {Found {COUNT} weak password} - other {Found {COUNT} weak passwords}} - {NUM_WEAK, plural, =0 {No weak passwords} @@ -597,485 +609,6 @@ =1 {1 reused password} other {{NUM_REUSED} reused passwords}} - - {COUNT, plural, - =0 {No security issues found} - =1 {Found {COUNT} security issue} - other {Found {COUNT} security issues}} - - - Check again - - - Try again - - - Checking passwords ($16 of $231)… - - - Cancel - - - Just now - - - Compromised passwords - - - Change these passwords immediately to keep your account safe: - - - Dismissed warnings ($12) - - - Weak passwords - - - Weak passwords are easy to guess. Make sure you're creating strong passwords. <a target='_blank' href='$1'>See more security tips.</a> - - - Change password - - - Open the app to change your password - - - Found in data breach - - - Entered on deceptive site - - - Entered on deceptive site and found in data breach - - - Show password - - - Hide password - - - Remove password - - - Dismiss warning - - - Restore warning - - - Remove password? - - - Removing this password will not delete your account on $1airbnb.com. Change your password or delete your account on $2<a href="https://airbnb.com" target="_blank">airbnb.com</a> to keep it safe from others. - - - App - - - Already changed this password? - - - Did you already change this password on $1airbnb.com? - - - Offer to save passwords - - - Auto Sign-in - - - Automatically sign in to sites and apps using saved credentials. If turned off, you'll be asked for confirmation every time before signing in to a site or app. - - - Warn you if passwords are exposed in a data breach - - - Warn you if a password was compromised in a data breach - - - When you sign in to your Brave sync chain, this feature is turned on. - - - Saved Passwords - - - Never Saved - - - Delete this item - - - Remove - - - Move to Brave sync chain - - - Search passwords - - - Password details - - - Details - - - Edit password - - - Edit password - - - Make sure the password you are saving matches your password for $1airbnb.com - - - You already saved a password with this username for $1website.com - - - View password - - - View password with username $1username for $2website.com - - - Did you mean $1twitter.com? - - - Add password - - - Make sure you're saving your current password for this site - - - Save to Brave Password Manager ($1username@gmail.com) - - - Copy password - - - Send password - - - Copy username - - - Site - - - App ($1com.netflix.mediaclient) - - - Username - - - Password - - - Note - - - No note added - - - $1950/$21000 - - - Notes can save up to $11000 characters. - - - Brave Password Manager timed out - - - {NUM_MINS, plural, - =1 {To keep your passwords safe, Brave Password Manager locks after 1 minute of inactivity} - other {To keep your passwords safe, Brave Password Manager locks after {NUM_MINS} minutes of inactivity}} - - - Enter your username - - - Site - - - Edit passkey - - - When you edit your passkey, your $1relyingPartyId account won't change - - - Saved addresses will appear here - - - Saved payment methods will appear here - - - Saved passwords will appear here - - - Saved passwords will appear here. <a href="#" > Import passwords</a> - - - Sites which never save passwords will appear here - - - Undo - - - Password deleted - - - Your password is saved on this device - - - Your password is saved in your Brave sync chain - - - Your password is saved on this device and in your Brave sync chain - - - Password deleted from your Brave sync chain - - - Password deleted from this device - - - Password deleted from this device and your Brave sync chain - - - Password copied to clipboard - - - Username copied to clipboard - - - To easily use them on all your devices, you can move them to your Brave sync chain - - - {COUNT, plural, - =1 {{COUNT} password is saved on this device} - other {{COUNT} passwords are saved on this device}} - - - Choose which passwords to move. You can access them whenever you're signed in. - - - Move passwords from this device to your Brave sync chain? - - - Passwords moved to your Brave sync chain - - - Move passwords - - - Don't move - - - Get started - - - Delete password? - - - Your password for <b>$1</b> is saved on this device and to your Brave sync chain. Which one do you want to delete? - - - Delete - - - Cancel - - - From your Brave sync chain - - - From this device - - - See and manage passwords saved on this device - - - View and manage saved passwords in your Brave sync chain - - - You can also show passwords from your <a is="action-link" href="$1" target="_blank">Brave sync chain</a> here - - - Show - - - Showing passwords from your <a is="action-link" href="$1" target="_blank">Brave sync chain</a> - - - Remove from device - - - Import passwords - - - Import passwords - - - Import successful! - - - Import complete - - - Something went wrong - - - Select file - - - To import passwords, select a CSV file - - - To import passwords to Brave Password Manager for elisa.g.becket@gmail.com$1, select a CSV file - - - To import passwords to Brave Password Manager on this device, select a CSV file - - - {NUM_PASSWORDS, plural, - =1 {1 password imported to Brave Password Manager on this device} - other {{NUM_PASSWORDS} passwords imported to Brave Password Manager on this device}} - - - {NUM_PASSWORDS, plural, - =1 {1 password imported to Brave Password Manager for elisa.g.becket@gmail.com$1} - other {{NUM_PASSWORDS} passwords imported to Brave Password Manager for elisa.g.becket@gmail.com$1}} - - - Select where to import your passwords - - - Consider deleting <span class="file-name">$1</span><span class="file-name">filename.csv</span>, so others who use this device can't see your passwords - - - Delete <span class="file-name">$1</span><span class="file-name">filename.csv</span>, so others who use this device can't see your passwords - - - Your passwords weren't imported - - - Can't import passwords. Check <span class="file-name">$1</span><span class="file-name">filename.csv</span> and make sure it's formatted correctly. <a href="$2" target="_blank">Learn more</a> - - - Can't import passwords. The file size should be less than 150 KB. - - - Can't import passwords. You can only import up to 3000$1 passwords at a time. - - - A password is required - - - A URL is required - - - URL format should be https://www.example.com - - - {NUM_PASSWORDS, plural, - =1 {1 other password wasn't imported because it's formatted incorrectly} - other {{NUM_PASSWORDS} other passwords weren't imported because they're formatted incorrectly}} - - - URL is more than 2048 characters - - - Username is more than 1000 characters - - - Password is more than 1000 characters - - - Note is more than 1000 characters - - - A password for this account is already saved to your Brave Password Manager (elisa.g.becket@gmail.com$1) - - - A password for this account is already saved on this device - - - {NUM_PASSWORDS, plural, - =1 {1 password not imported} - other {{NUM_PASSWORDS} passwords not imported}} - - - {NUM_PASSWORDS, plural, - =1 {1 existing password found} - other {{NUM_PASSWORDS} existing passwords found}} - - - You already have passwords for these accounts in your $1Brave Password Manager. If you choose to import one of the passwords below, it will replace the existing one. - - - Cancel import - - - Skip - - - Replace - - - You're already importing passwords in another tab - - - Export passwords - - - Export passwords - - - Your passwords will be visible to anyone who can see the exported file. - - - Export passwords - - - Try again - - - Exporting passwords... - - - Can't export passwords to "$1Documents" - - - Try the following tips: - - - Make sure there is enough space on your device - - - Export your passwords to another folder - - - More actions, password for $1example@gmail.com on $2www.google.com - - - More actions, saved account for $1example@gmail.com on $2www.google.com - - - Saved passwords table - - - Credential details for $1example@gmail.com on $2www.google.com - - - On-device encryption - - - For added safety, encrypt passwords on your device before they‘re saved to Brave Password Manager - - - Your passwords are encrypted on your device before they‘re saved to Brave Password Manager - @@ -1552,6 +1085,12 @@ Performance + + Memory + + + Speed + Memory Saver @@ -1579,20 +1118,26 @@ Always keep these sites active + + Sites you add will always stay active and memory won't be freed up from them + Additional sites Add current sites + + No sites currently available. Visit a site to add it to this list. + Add sites manually Active site - - Sites you add will always stay active and memory won't be freed up from them. <a href="$1" target="_blank">Learn more about site exclusion</a> + + Sites you add will always stay active and memory won't be freed up from them. <a href="$1" target="_blank">Learn more about keeping specific sites active</a> Power @@ -1609,6 +1154,9 @@ Energy saver options + + Turn on Energy Saver to extend battery life + @@ -1776,19 +1324,16 @@ No preloading - Pages load only after you open them. + Pages load only after you open them Standard preloading - Some of the pages you visit are preloaded. + Some of the pages you visit are preloaded - Browsing and searching is faster. - - - Brave preloads pages you're likely to visit, so that they load more quickly when you visit them. + Browsing and searching is faster Extended preloading @@ -1797,16 +1342,7 @@ More pages are preloaded. Pages may be preloaded through Brave servers when requested by other sites. - Browsing and searching is faster than standard preloading. - - - Brave preloads even more pages that you're likely to visit, so that they load more quickly when you visit them. - - - When a site asks to privately preload links on their page, Brave uses Brave servers. This hides your identity from the preloaded site, but Brave learns what sites get preloaded. - - - If you allow cookies, Brave may use them when preloading. + Browsing and searching is faster than standard preloading @@ -2293,6 +1829,14 @@ Detects and warns you about dangerous events when they happen + + + Sends an obfuscated portion of the URL to Brave through a privacy server that hides your IP address + + + If a site tries to steal your password, or when you download a harmful file, Brave may also send URLs, including bits of page content, to Brave + + Choose whether to get additional search suggestions @@ -2557,9 +2101,6 @@ Undo - - Preload pages for faster browsing and searching - Uses cookies to remember your preferences, even if you don’t visit those pages @@ -2584,6 +2125,9 @@ Faster, proactive protection against dangerous websites, downloads, and extensions. Warns you about password breaches. Requires browsing data to be sent to Brave. + + Real-time, proactive protection against dangerous sites, downloads, and extensions that's based on your browsing data getting sent to Brave + Show enhanced protection details @@ -2599,6 +2143,33 @@ Sends URLs to Safe Browsing to check them. Also sends a small sample of pages, downloads, extension activity, and system information to help discover new threats. Temporarily links this data to your Brave sync chain when you're signed in, to protect you across Brave apps. + + When on + + + In-depth scans for suspicious downloads. + + + When you're signed in, protects you across Brave services. + + + Improves security for you and everyone on the web. + + + Warns you if you use a password that has been compromised in a data breach. + + + Things to consider + + + Sends the URLs of sites you visit and a small sample of page content, downloads, extension activity, and system information to Google Safe Browsing to check if they're harmful. + + + When you're signed in, this data is linked to your Brave sync chain to protect you across Brave services, for example increasing protection in Gmail after a security incident. + + + Doesn't noticeably slow down your browser or device. + Standard protection @@ -2608,6 +2179,14 @@ Protects against sites, downloads, and extensions that are known to be dangerous. If a page does something suspicious, URLs and bits of page content are sent to Google Safe Browsing. + + + Protects against sites, downloads, and extensions that are known to be dangerous. When you visit a site, Brave sends an obfuscated portion of the URL to Brave through a privacy server that hides your IP address. If a site does something suspicious, full URLs and bits of page content are also sent. + + + Sends an obfuscated portion of the URL to Brave through a privacy server that hides your IP address. If a site tries to steal your password, or when you download a harmful file, Brave may also send URLs, including bits of page content, to Brave. + + Show standard protection details @@ -2623,6 +2202,9 @@ Does not protect you against dangerous websites, downloads, and extensions. You’ll still get Safe Browsing protection, where available, in other Brave services, like Gmail and Search. + + Does not protect you against dangerous websites, downloads, and extensions. Your Safe Browsing settings in other Brave products won't be affected. + Turn off Safe Browsing? @@ -3056,6 +2638,21 @@ Not allowed to automatically download multiple files + + Sites might open a picture-in-picture window when you change to a different tab + + + Sites can open a picture-in-picture window when you change to a different tab + + + Don't allow sites to open a picture-in-picture window when you change to a different tab + + + Allowed to open a picture-in-picture window when you change to a different tab + + + Not allowed to open a picture-in-picture window when you change to a different tab + After you leave a site, it can keep syncing to finish tasks, like uploading photos or sending a chat message @@ -4039,10 +3636,10 @@ Sites are blocked from asking you to use info they've saved about you - You allowed these sites to use info they've saved about you + Allowed to use info they've saved about you - You blocked these sites from using info they've saved about you + Not allowed to use info they've saved about you Remove $1google.com @@ -4646,6 +4243,7 @@ + Safety Hub @@ -4661,4 +4259,13 @@ Safety tips + + Nothing else needs your attention right now + + + Checked just now + + + Checked $12 days ago + diff --git a/app/settings_strings_override.grdp b/app/settings_strings_override.grdp index 0e11477d14c5..6c4ef4ba6117 100644 --- a/app/settings_strings_override.grdp +++ b/app/settings_strings_override.grdp @@ -29,6 +29,12 @@ + + + + + + @@ -125,6 +131,8 @@ When you’re in Private mode, sites can only use cookies to see your browsing activity on their own site. Cookies are deleted at the end of the Private session. + + When you click or type in the address bar or search box, you'll see suggestions from your default search engine. This is off in Private. @@ -133,6 +141,8 @@ =1 {Review <b>1 extension</b> that was taken down from the Web Store} other {Review <b>{NUM_EXTENSIONS} extensions</b> that were taken down from the Web Store}} + + diff --git a/app/shared_settings_strings.grdp b/app/shared_settings_strings.grdp index acd69f8dafdd..98a30354a7ca 100644 --- a/app/shared_settings_strings.grdp +++ b/app/shared_settings_strings.grdp @@ -334,6 +334,9 @@ Passwords + + Passwords and passkeys + Passphrase @@ -403,19 +406,6 @@ You can turn on sync anytime in settings - - - - Changes you make here apply only to Brave Browser. To make changes to your Lacros Brave Browser settings, open Lacros Brave Browser and go to settings. - - - - - - - Changes you make here apply only to Lacros Brave Browser. To make changes to your Brave Browser settings, open Brave Browser and go to settings. - - diff --git a/app/shared_settings_strings_override.grdp b/app/shared_settings_strings_override.grdp index 804e06c3f899..736e40d9d7a4 100644 --- a/app/shared_settings_strings_override.grdp +++ b/app/shared_settings_strings_override.grdp @@ -10,12 +10,6 @@ - - - - - - diff --git a/browser/brave_ads/application_state/background_helper/background_helper_mac.mm b/browser/brave_ads/application_state/background_helper/background_helper_mac.mm index e57c82bfe333..08be0516e882 100644 --- a/browser/brave_ads/application_state/background_helper/background_helper_mac.mm +++ b/browser/brave_ads/application_state/background_helper/background_helper_mac.mm @@ -7,9 +7,9 @@ #import +#include "base/apple/foundation_util.h" +#include "base/apple/osstatus_logging.h" #include "base/logging.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mac_logging.h" #include "base/mac/mac_util.h" #include "base/memory/raw_ptr.h" diff --git a/browser/brave_ads/device_id/device_id_impl_mac.cc b/browser/brave_ads/device_id/device_id_impl_mac.cc index 83aa7553564e..d9f975e73961 100644 --- a/browser/brave_ads/device_id/device_id_impl_mac.cc +++ b/browser/brave_ads/device_id/device_id_impl_mac.cc @@ -17,12 +17,12 @@ #include #include +#include "base/apple/foundation_util.h" +#include "base/apple/scoped_cftyperef.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/location.h" -#include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_ioobject.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" @@ -76,30 +76,31 @@ std::string GetVolumeUUIDFromBSDName(const std::string& bsd_name) { const CFAllocatorRef allocator = nullptr; - const base::ScopedCFTypeRef session(DASessionCreate(allocator)); + const base::apple::ScopedCFTypeRef session( + DASessionCreate(allocator)); if (!session) { return {}; } - const base::ScopedCFTypeRef disk( + const base::apple::ScopedCFTypeRef disk( DADiskCreateFromBSDName(allocator, session, bsd_name.c_str())); if (!disk) { return {}; } - const base::ScopedCFTypeRef disk_description( + const base::apple::ScopedCFTypeRef disk_description( DADiskCopyDescription(disk)); if (!disk_description) { return {}; } - const CFUUIDRef volume_uuid = base::mac::GetValueFromDictionary( + const CFUUIDRef volume_uuid = base::apple::GetValueFromDictionary( disk_description, kDADiskDescriptionVolumeUUIDKey); if (volume_uuid == nullptr) { return {}; } - const base::ScopedCFTypeRef volume_uuid_as_string( + const base::apple::ScopedCFTypeRef volume_uuid_as_string( CFUUIDCreateString(allocator, volume_uuid)); if (!volume_uuid_as_string) { return {}; @@ -129,7 +130,7 @@ class MacAddressProcessor { bool ProcessNetworkController(io_object_t network_controller) { bool keep_going = true; - const base::ScopedCFTypeRef mac_address_data( + const base::apple::ScopedCFTypeRef mac_address_data( static_cast(IORegistryEntryCreateCFProperty( network_controller, CFSTR(kIOMACAddress), kCFAllocatorDefault, 0))); if (!mac_address_data) { @@ -145,7 +146,7 @@ class MacAddressProcessor { mac_address_ = base::ToLowerASCII(base::HexEncode(mac_address, mac_address_size)); - base::ScopedCFTypeRef provider_class_string( + base::apple::ScopedCFTypeRef provider_class_string( static_cast(IORegistryEntryCreateCFProperty( network_controller, CFSTR(kIOProviderClassKey), kCFAllocatorDefault, 0))); diff --git a/browser/brave_app_controller_mac_browsertest.mm b/browser/brave_app_controller_mac_browsertest.mm index f51b14fd4c89..5610973a1ee6 100644 --- a/browser/brave_app_controller_mac_browsertest.mm +++ b/browser/brave_app_controller_mac_browsertest.mm @@ -10,8 +10,8 @@ #include -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_objc_class_swizzler.h" +#include "base/apple/foundation_util.h" +#include "base/apple/scoped_objc_class_swizzler.h" #include "base/test/scoped_feature_list.h" #include "brave/app/brave_command_ids.h" #include "brave/browser/brave_app_controller_mac.h" @@ -85,7 +85,7 @@ EXPECT_TRUE(omnibox_view->IsSelectAll()); EXPECT_TRUE(BraveBrowserWindow::From(browser()->window())->HasSelectedURL()); - BraveAppController* ac = base::mac::ObjCCastStrict( + BraveAppController* ac = base::apple::ObjCCastStrict( [[NSApplication sharedApplication] delegate]); ASSERT_TRUE(ac); NSMenu* edit_submenu = [[[NSApp mainMenu] itemWithTag:IDC_EDIT_MENU] submenu]; @@ -117,7 +117,7 @@ EXPECT_TRUE(omnibox_view->IsSelectAll()); EXPECT_TRUE(BraveBrowserWindow::From(browser()->window())->HasSelectedURL()); - BraveAppController* ac = base::mac::ObjCCastStrict( + BraveAppController* ac = base::apple::ObjCCastStrict( [[NSApplication sharedApplication] delegate]); ASSERT_TRUE(ac); @@ -145,7 +145,7 @@ omnibox_view->SetUserText(u"any text"); omnibox_view->SelectAll(false); EXPECT_TRUE(omnibox_view->IsSelectAll()); - AppController* ac = base::mac::ObjCCastStrict( + AppController* ac = base::apple::ObjCCastStrict( [[NSApplication sharedApplication] delegate]); ASSERT_TRUE(ac); @@ -178,7 +178,7 @@ EXPECT_FALSE(omnibox_view->IsSelectAll()); EXPECT_FALSE(BraveBrowserWindow::From(browser()->window())->HasSelectedURL()); - BraveAppController* ac = base::mac::ObjCCastStrict( + BraveAppController* ac = base::apple::ObjCCastStrict( [[NSApplication sharedApplication] delegate]); ASSERT_TRUE(ac); @@ -194,7 +194,7 @@ IN_PROC_BROWSER_TEST_F(BraveAppControllerBrowserTest, BookmarkItemsFromMenuBarTest) { AppController* ac = - base::mac::ObjCCastStrict([NSApp delegate]); + base::apple::ObjCCastStrict([NSApp delegate]); [ac mainMenuCreated]; [ac setLastProfile:browser()->profile()]; diff --git a/browser/brave_autofill_browsertest.cc b/browser/brave_autofill_browsertest.cc index b05e26a59ff7..1f8294590489 100644 --- a/browser/brave_autofill_browsertest.cc +++ b/browser/brave_autofill_browsertest.cc @@ -60,7 +60,7 @@ class BraveAutofillBrowserTest : public InProcessBrowserTest { ->DriverForFrame(active_contents->GetPrimaryMainFrame()); ASSERT_TRUE(cross_driver); EXPECT_EQ(static_cast( - cross_driver->autofill_manager()) + &cross_driver->GetAutofillManager()) ->IsAutofillEnabled(), enabled); } diff --git a/browser/brave_prefs_browsertest.cc b/browser/brave_prefs_browsertest.cc index 76ac4e5d7c44..b8c3303e5ce4 100644 --- a/browser/brave_prefs_browsertest.cc +++ b/browser/brave_prefs_browsertest.cc @@ -168,8 +168,6 @@ IN_PROC_BROWSER_TEST_F(BraveProfilePrefsBrowserTest, // Verify cloud print is disabled. EXPECT_FALSE(chrome_test_utils::GetProfile(this)->GetPrefs()->GetBoolean( prefs::kCloudPrintProxyEnabled)); - EXPECT_FALSE(chrome_test_utils::GetProfile(this)->GetPrefs()->GetBoolean( - prefs::kCloudPrintSubmitEnabled)); #if !BUILDFLAG(IS_ANDROID) EXPECT_TRUE(chrome_test_utils::GetProfile(this)->GetPrefs()->GetBoolean( ntp_prefs::kNtpUseMostVisitedTiles)); diff --git a/browser/brave_profile_prefs.cc b/browser/brave_profile_prefs.cc index a17b4a6000f7..98e6269239d0 100644 --- a/browser/brave_profile_prefs.cc +++ b/browser/brave_profile_prefs.cc @@ -401,9 +401,6 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { // Cloud Print: Don't allow this browser to act as Cloud Print server registry->SetDefaultPrefValue(prefs::kCloudPrintProxyEnabled, base::Value(false)); - // Cloud Print: Don't allow jobs to be submitted - registry->SetDefaultPrefValue(prefs::kCloudPrintSubmitEnabled, - base::Value(false)); // Disable default webstore icons in topsites or apps. registry->SetDefaultPrefValue(policy::policy_prefs::kHideWebStoreIcon, diff --git a/browser/brave_shell_integration_win.cc b/browser/brave_shell_integration_win.cc index 168380ba9cab..6ba97c6f7e2c 100644 --- a/browser/brave_shell_integration_win.cc +++ b/browser/brave_shell_integration_win.cc @@ -183,21 +183,18 @@ void PinToTaskbar(Profile* profile, if (profile) profile_path = profile->GetPath(); - // TODO(simonhong): handle connection error state if caller wants. - GetIsPinnedToTaskbarState( - base::DoNothing(), - base::BindOnce( - [](const base::FilePath& profile_path, - base::OnceCallback result_callback, bool succeeded, - bool is_pinned_to_taskbar) { - if (succeeded && is_pinned_to_taskbar) { - // Early return. Already pinned. - std::move(result_callback).Run(true); - return; - } - DoPinToTaskbar(profile_path, std::move(result_callback)); - }, - std::move(profile_path), std::move(result_callback))); + GetIsPinnedToTaskbarState(base::BindOnce( + [](const base::FilePath& profile_path, + base::OnceCallback result_callback, bool succeeded, + bool is_pinned_to_taskbar) { + if (succeeded && is_pinned_to_taskbar) { + // Early return. Already pinned. + std::move(result_callback).Run(true); + return; + } + DoPinToTaskbar(profile_path, std::move(result_callback)); + }, + std::move(profile_path), std::move(result_callback))); } void IsShortcutPinned(base::OnceCallback result_callback) { @@ -208,14 +205,12 @@ void IsShortcutPinned(base::OnceCallback result_callback) { return; } - GetIsPinnedToTaskbarState( - base::DoNothing(), - base::BindOnce( - [](base::OnceCallback result_callback, bool succeeded, - bool is_pinned_to_taskbar) { - std::move(result_callback).Run(succeeded && is_pinned_to_taskbar); - }, - std::move(result_callback))); + GetIsPinnedToTaskbarState(base::BindOnce( + [](base::OnceCallback result_callback, bool succeeded, + bool is_pinned_to_taskbar) { + std::move(result_callback).Run(succeeded && is_pinned_to_taskbar); + }, + std::move(result_callback))); } } // namespace shell_integration::win diff --git a/browser/brave_wallet/brave_wallet_service_unittest.cc b/browser/brave_wallet/brave_wallet_service_unittest.cc index 313951ba7571..85923018eb34 100644 --- a/browser/brave_wallet/brave_wallet_service_unittest.cc +++ b/browser/brave_wallet/brave_wallet_service_unittest.cc @@ -50,6 +50,7 @@ #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "ui/base/l10n/l10n_util.h" #include "url/origin.h" diff --git a/browser/brave_wallet/ethereum_provider_impl_unittest.cc b/browser/brave_wallet/ethereum_provider_impl_unittest.cc index 0c04345e2601..ca81aa40dce4 100644 --- a/browser/brave_wallet/ethereum_provider_impl_unittest.cc +++ b/browser/brave_wallet/ethereum_provider_impl_unittest.cc @@ -236,8 +236,9 @@ class EthereumProviderImplUnitTest : public testing::Test { profile_.SetPermissionControllerDelegate( base::WrapUnique(static_cast( - PermissionManagerFactory::GetInstance()->BuildServiceInstanceFor( - browser_context())))); + PermissionManagerFactory::GetInstance() + ->BuildServiceInstanceForBrowserContext(browser_context()) + .release()))); provider_ = std::make_unique( host_content_settings_map(), json_rpc_service(), tx_service(), diff --git a/browser/brave_wallet/solana_provider_impl_unittest.cc b/browser/brave_wallet/solana_provider_impl_unittest.cc index ea6764823329..9b872a5df07b 100644 --- a/browser/brave_wallet/solana_provider_impl_unittest.cc +++ b/browser/brave_wallet/solana_provider_impl_unittest.cc @@ -142,8 +142,9 @@ class SolanaProviderImplUnitTest : public testing::Test { brave_wallet::TxServiceFactory::GetServiceForContext(browser_context()); profile_.SetPermissionControllerDelegate( base::WrapUnique(static_cast( - PermissionManagerFactory::GetInstance()->BuildServiceInstanceFor( - browser_context())))); + PermissionManagerFactory::GetInstance() + ->BuildServiceInstanceForBrowserContext(browser_context()) + .release()))); auto* host_content_settings_map = HostContentSettingsMapFactory::GetForProfile(browser_context()); ASSERT_TRUE(host_content_settings_map); diff --git a/browser/download/bubble/download_display_controller_unittest.cc b/browser/download/bubble/download_display_controller_unittest.cc index 86c706c5b8d6..43e07c615bc0 100644 --- a/browser/download/bubble/download_display_controller_unittest.cc +++ b/browser/download/bubble/download_display_controller_unittest.cc @@ -119,6 +119,8 @@ class FakeDownloadDisplay : public DownloadDisplay { DownloadIconState GetDownloadIconState() { return icon_state_; } bool IsActive() { return is_active_; } void SetIsFullscreen(bool is_fullscreen) { is_fullscreen_ = is_fullscreen; } + void OpenSecuritySubpage( + const offline_items_collection::ContentId&) override {} private: bool shown_ = false; diff --git a/browser/mac/sparkle_glue.mm b/browser/mac/sparkle_glue.mm index ba56c4577420..99a4421c7c44 100644 --- a/browser/mac/sparkle_glue.mm +++ b/browser/mac/sparkle_glue.mm @@ -10,9 +10,9 @@ #include #include "base/apple/bundle_locations.h" +#include "base/apple/foundation_util.h" +#import "base/apple/scoped_nsautorelease_pool.h" #include "base/command_line.h" -#include "base/mac/foundation_util.h" -#import "base/mac/scoped_nsautorelease_pool.h" #include "base/memory/ref_counted.h" #include "base/strings/sys_string_conversions.h" #include "base/system/sys_info.h" @@ -175,7 +175,7 @@ - (NSString*)currentlyInstalledVersion { NSString* appInfoPlistPath = [self appInfoPlistPath]; NSDictionary* infoPlist = [NSDictionary dictionaryWithContentsOfFile:appInfoPlistPath]; - return base::mac::ObjCCast( + return base::apple::ObjCCast( [infoPlist objectForKey:@"CFBundleShortVersionString"]); } @@ -250,7 +250,7 @@ - (void)loadParameters { - (AutoupdateStatus)recentStatus { NSDictionary* dictionary = _recentNotification.userInfo; - NSNumber* status = base::mac::ObjCCastStrict( + NSNumber* status = base::apple::ObjCCastStrict( [dictionary objectForKey:kAutoupdateStatusStatus]); return static_cast(status.intValue); } diff --git a/browser/net/brave_localhost_permission_network_delegate_helper.cc b/browser/net/brave_localhost_permission_network_delegate_helper.cc index 40a53eca07ce..8e1041afecbc 100644 --- a/browser/net/brave_localhost_permission_network_delegate_helper.cc +++ b/browser/net/brave_localhost_permission_network_delegate_helper.cc @@ -142,8 +142,10 @@ int OnBeforeURLRequest_LocalhostPermissionWork( if (localhost_permission_component->CanAskForLocalhostPermission( request_initiator_url)) { permission_controller->RequestPermissionsFromCurrentDocument( - {blink::PermissionType::BRAVE_LOCALHOST_ACCESS}, - /* rfh */ contents->GetPrimaryMainFrame(), true, + /* rfh */ contents->GetPrimaryMainFrame(), + content::PermissionRequestDescription( + blink::PermissionType::BRAVE_LOCALHOST_ACCESS, + /*user_gesture*/ true), base::BindOnce(&OnPermissionRequestStatus, ctx->frame_tree_node_id)); } diff --git a/browser/permissions/brave_wallet_permission_context_unittest.cc b/browser/permissions/brave_wallet_permission_context_unittest.cc index 14c33e6e1583..0e9f726f47a4 100644 --- a/browser/permissions/brave_wallet_permission_context_unittest.cc +++ b/browser/permissions/brave_wallet_permission_context_unittest.cc @@ -30,8 +30,9 @@ class BraveWalletPermissionContextUnitTest : public testing::Test { map_ = HostContentSettingsMapFactory::GetForProfile(&profile_); profile_.SetPermissionControllerDelegate( base::WrapUnique(static_cast( - PermissionManagerFactory::GetInstance()->BuildServiceInstanceFor( - browser_context())))); + PermissionManagerFactory::GetInstance() + ->BuildServiceInstanceForBrowserContext(browser_context()) + .release()))); } void TearDown() override { diff --git a/browser/profiles/brave_profile_manager.cc b/browser/profiles/brave_profile_manager.cc index 00163b95c1d9..5a6ab8800ea2 100644 --- a/browser/profiles/brave_profile_manager.cc +++ b/browser/profiles/brave_profile_manager.cc @@ -168,7 +168,7 @@ void BraveProfileManager::MigrateProfileNames() { // e.g. 'Person X' --> 'Profile X'. ProfileAttributesStorage& storage = GetProfileAttributesStorage(); std::vector entries = - storage.GetAllProfilesAttributesSortedByName(); + storage.GetAllProfilesAttributesSortedByNameWithCheck(); // Make sure we keep the numbering the same. for (auto* entry : entries) { // Rename the necessary profiles. Don't check for legacy names as profile diff --git a/browser/profiles/brave_profile_manager_browsertest.cc b/browser/profiles/brave_profile_manager_browsertest.cc index 8d2197682c2b..ee835b426ba5 100644 --- a/browser/profiles/brave_profile_manager_browsertest.cc +++ b/browser/profiles/brave_profile_manager_browsertest.cc @@ -117,8 +117,7 @@ IN_PROC_BROWSER_TEST_F(BraveProfileManagerTest, ProfileAttributesStorage& storage = profile_manager->GetProfileAttributesStorage(); auto profile_data = GetTestProfileData(profile_manager); - auto entries = - storage.GetAllProfilesAttributesSortedByName(); + auto entries = storage.GetAllProfilesAttributesSortedByNameWithCheck(); // Verify we still have the expected number of profiles. ASSERT_EQ(entries.size(), profile_data.size()); // Order of items in entries and profile_data should be the same diff --git a/browser/resources/settings/brave_overrides/cookies_page.ts b/browser/resources/settings/brave_overrides/cookies_page.ts index 08a96b06b8ac..9eed76f14fca 100644 --- a/browser/resources/settings/brave_overrides/cookies_page.ts +++ b/browser/resources/settings/brave_overrides/cookies_page.ts @@ -35,7 +35,7 @@ RegisterPolymerTemplateModifications({ } } const preloadingLinkRowTemplate = templateContent.querySelector( - 'template[is=dom-if][if="[[showPreloadingSubPage_]]"]') + 'template[is=dom-if][if="[[showPreloadingSubpage_]]"]') if (!preloadingLinkRowTemplate) { console.error( '[Brave Settings Overrides] Could not find preloading template') diff --git a/browser/tor/brave_tor_browsertest.cc b/browser/tor/brave_tor_browsertest.cc index ea86dbeeafc7..9c1441d015a4 100644 --- a/browser/tor/brave_tor_browsertest.cc +++ b/browser/tor/brave_tor_browsertest.cc @@ -77,7 +77,7 @@ void TestAutofillInWindow(content::WebContents* active_contents, ->DriverForFrame(active_contents->GetPrimaryMainFrame()); ASSERT_TRUE(cross_driver); EXPECT_EQ(static_cast( - cross_driver->autofill_manager()) + &cross_driver->GetAutofillManager()) ->IsAutofillEnabled(), enabled); } diff --git a/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml b/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml index a221c05580cc..936c52d9cef7 100644 --- a/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml +++ b/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_header_item.xml @@ -1,36 +1,42 @@ - + - + - + - + diff --git a/browser/ui/android/omnibox/BUILD.gn b/browser/ui/android/omnibox/BUILD.gn index 0a10d1c4091a..9c78ca70e4a5 100644 --- a/browser/ui/android/omnibox/BUILD.gn +++ b/browser/ui/android/omnibox/BUILD.gn @@ -1,6 +1,7 @@ -# Copyright 2022 The Brave Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. +# Copyright (c) 2022 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. import("//build/config/android/config.gni") import("//build/config/android/rules.gni") @@ -18,7 +19,6 @@ android_library("java") { "java/src/org/chromium/chrome/browser/omnibox/suggestions/brave_search/BraveSearchBannerProcessor.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/brave_search/BraveSearchBannerProperties.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/brave_search/BraveSearchBannerViewBinder.java", - "java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/BraveEditUrlSuggestionProcessor.java", ] deps = [ @@ -41,6 +41,7 @@ android_library("java") { "//components/prefs/android:java", "//components/search_engines/android:java", "//components/user_prefs/android:java", + "//content/public/android:content_full_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_recyclerview_recyclerview_java", "//ui/android:ui_no_recycler_view_java", diff --git a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListBuilder.java b/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListBuilder.java index c6a91765fbaa..92d0b44dd92b 100644 --- a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListBuilder.java +++ b/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListBuilder.java @@ -25,6 +25,7 @@ import org.chromium.chrome.browser.search_engines.settings.BraveSearchEngineAdapter; import org.chromium.chrome.browser.tab.Tab; import org.chromium.components.omnibox.AutocompleteResult; +import org.chromium.components.omnibox.GroupsProto.GroupConfig; import org.chromium.ui.modelutil.PropertyModel; import java.util.Arrays; @@ -62,9 +63,9 @@ void initDefaultProcessors(Context context, SuggestionHost host, AutocompleteDel } @Override - void onUrlFocusChange(boolean hasFocus) { - super.onUrlFocusChange(hasFocus); - mBraveSearchBannerProcessor.onUrlFocusChange(hasFocus); + void onOmniboxSessionStateChange(boolean activated) { + super.onOmniboxSessionStateChange(activated); + mBraveSearchBannerProcessor.onOmniboxSessionStateChange(activated); } @Override @@ -83,8 +84,8 @@ List buildDropdownViewInfoList(AutocompleteResult autocomp if (isBraveSearchPromoBanner()) { final PropertyModel model = mBraveSearchBannerProcessor.createModel(); mBraveSearchBannerProcessor.populateModel(model); - viewInfoList.add(new DropdownItemViewInfo(mBraveSearchBannerProcessor, model, - BraveSearchBannerProcessor.BRAVE_SEARCH_PROMO_GROUP)); + viewInfoList.add(new DropdownItemViewInfo( + mBraveSearchBannerProcessor, model, GroupConfig.getDefaultInstance())); } return viewInfoList; diff --git a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListManager.java b/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListManager.java index 432b0fa0f071..0403099922fc 100644 --- a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListManager.java +++ b/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/BraveDropdownItemViewInfoListManager.java @@ -11,7 +11,6 @@ import androidx.annotation.NonNull; -import org.chromium.components.omnibox.suggestions.OmniboxSuggestionUiType; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; class BraveDropdownItemViewInfoListManager extends DropdownItemViewInfoListManager { @@ -25,21 +24,20 @@ class BraveDropdownItemViewInfoListManager extends DropdownItemViewInfoListManag } /** - * Remove all suggestions that belong to specific group. - * - * @param groupId Group ID of suggestions that should be removed. + * Removes Brave search suggestion. */ - public void removeSuggestionsForGroup(int groupId) { + public void removeBraveSearchSuggestion() { int index; int count = 0; for (index = mManagedModel.size() - 1; index >= 0; index--) { DropdownItemViewInfo viewInfo = (DropdownItemViewInfo) mManagedModel.get(index); - if (isGroupHeaderWithId(viewInfo, groupId)) { - break; - } else if (viewInfo.groupId == groupId) { + if (viewInfo.processor.getViewTypeId() + == BraveOmniboxSuggestionUiType.BRAVE_SEARCH_PROMO_BANNER) { count++; - } else if (count > 0 && viewInfo.groupId != groupId) { + } else if (count > 0 + && viewInfo.processor.getViewTypeId() + != BraveOmniboxSuggestionUiType.BRAVE_SEARCH_PROMO_BANNER) { break; } } @@ -48,9 +46,4 @@ public void removeSuggestionsForGroup(int groupId) { mManagedModel.removeRange(index + 1, count); } } - - /** @return Whether the supplied view info is a header for the specific group of suggestions. */ - private boolean isGroupHeaderWithId(DropdownItemViewInfo info, int groupId) { - return (info.type == OmniboxSuggestionUiType.HEADER && info.groupId == groupId); - } } diff --git a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/brave_search/BraveSearchBannerProcessor.java b/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/brave_search/BraveSearchBannerProcessor.java index 4c6e1af43267..7b54addaec7e 100644 --- a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/brave_search/BraveSearchBannerProcessor.java +++ b/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/brave_search/BraveSearchBannerProcessor.java @@ -24,7 +24,6 @@ public class BraveSearchBannerProcessor implements DropdownItemProcessor { private final int mMinimumHeight; private final UrlBarEditingTextStateProvider mUrlBarEditingTextProvider; private final AutocompleteDelegate mUrlBarDelegate; - public static final int BRAVE_SEARCH_PROMO_GROUP = 100; /** * @param context An Android context. @@ -46,7 +45,7 @@ public void onPositiveClicked() { mUrlBarDelegate.loadUrl("https://search.brave.com/search?q=" + mUrlBarEditingTextProvider.getTextWithoutAutocomplete() + "&action=makeDefault", - PageTransition.LINK, System.currentTimeMillis()); + PageTransition.LINK, System.currentTimeMillis(), /*openInNewTab=*/false); } @Override @@ -72,7 +71,7 @@ public PropertyModel createModel() { } @Override - public void onUrlFocusChange(boolean hasFocus) {} + public void onOmniboxSessionStateChange(boolean activated) {} @Override public void onNativeInitialized() {} diff --git a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/BraveEditUrlSuggestionProcessor.java b/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/BraveEditUrlSuggestionProcessor.java deleted file mode 100644 index eb2a30bad64d..000000000000 --- a/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/BraveEditUrlSuggestionProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2020 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package org.chromium.chrome.browser.omnibox.suggestions.editurl; - -import android.content.Context; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.omnibox.styles.OmniboxImageSupplier; -import org.chromium.chrome.browser.omnibox.suggestions.SuggestionHost; -import org.chromium.chrome.browser.omnibox.suggestions.UrlBarDelegate; -import org.chromium.chrome.browser.share.ShareDelegate; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.components.omnibox.AutocompleteMatch; - -public class BraveEditUrlSuggestionProcessor extends EditUrlSuggestionProcessor { - private boolean mHasClearedOmniboxForFocus; - - public BraveEditUrlSuggestionProcessor(Context context, SuggestionHost suggestionHost, - UrlBarDelegate locationBarDelegate, OmniboxImageSupplier imageSupplier, - Supplier tabSupplier, Supplier shareDelegateSupplier) { - super(context, suggestionHost, locationBarDelegate, imageSupplier, tabSupplier, - shareDelegateSupplier); - } - - @Override - public boolean doesProcessSuggestion(AutocompleteMatch suggestion, int position) { - // We don't want to clear omnibox for focus, so just pretend that it's already happened - mHasClearedOmniboxForFocus = true; - return super.doesProcessSuggestion(suggestion, position); - } -} diff --git a/browser/ui/android/strings/android_chrome_strings.grd b/browser/ui/android/strings/android_chrome_strings.grd index 110b8cf6fd27..362cbb9bb108 100644 --- a/browser/ui/android/strings/android_chrome_strings.grd +++ b/browser/ui/android/strings/android_chrome_strings.grd @@ -356,7 +356,7 @@ CHAR_LIMIT guidelines: No preloading - Pages load only after you open them. + Pages load only after you open them Standard preloading @@ -1500,6 +1500,18 @@ Your Brave account may have other forms of browsing history like searches and ac If you also share Brave usage reports, those reports include the URLs you visit + + From the address bar, you can open page info to see additional info about the page you're visiting + + + If you also save your bookmarks in your Brave sync chain, you can track product prices in Brave and get notified when the price drops + + + URLs you visit are sent to Brave to predict what sites you might visit next and to show you additional info about the page you're visiting + + + If you also share Brave usage reports, those reports include the URLs you visit + History sync @@ -1516,10 +1528,10 @@ Your Brave account may have other forms of browsing history like searches and ac Choose when to block third-party cookies - Block while using private + Block while using Private - While in private, sites can’t use your cookies to see your browsing activity across different sites, for example, to personalize ads. Features on some sites may break. + While in Private, sites can’t use your cookies to see your browsing activity across different sites, for example, to personalize ads. Features on some sites may break. Block all the time @@ -1581,9 +1593,15 @@ Your Brave account may have other forms of browsing history like searches and ac Checks URLs with a list of unsafe sites stored in Brave + + Sends an obfuscated portion of the URL to Brave through a privacy server that hides your IP address + If a site tries to steal your password, or when you download a harmful file, Brave may send URLs including bits of page content to Safe Browsing + + If a site tries to steal your password, or when you download a harmful file, Brave may send URLs including bits of page content to Brave + Predicts and warns you about dangerous events before they happen @@ -1605,6 +1623,15 @@ Your Brave account may have other forms of browsing history like searches and ac Temporarily links this data to your Brave sync chain when you’re signed in, to protect you across Brave apps + + When you tap or type in the address bar or search box, you'll see suggestions from your default search engine. This is off in Private. + + + What you type in the address bar or search box is sent to your default search engine + + + Depending on your settings, Brave may also send cookies and your current URL + @@ -1719,6 +1746,9 @@ Your Brave account may have other forms of browsing history like searches and ac Faster, proactive protection against dangerous websites, downloads, and extensions. Warns you about password breaches. Requires browsing data to be sent to Brave. + + Real-time, proactive protection against dangerous sites, downloads, and extensions that’s based on your browsing data getting sent to Brave + Standard protection @@ -1728,32 +1758,68 @@ Your Brave account may have other forms of browsing history like searches and ac Protects against sites, downloads, and extensions that are known to be dangerous. If a page does something suspicious, URLs and bits of page content are sent to Google Safe Browsing. + + Protects against sites, downloads, and extensions that are known to be dangerous. When you visit a site, Brave sends an obfuscated portion of the URL to Brave through a privacy server that hides your IP address. If a site does something suspicious, full URLs and bits of page content are also sent. + No protection (not recommended) Does not protect you against dangerous websites, downloads, and extensions. You’ll still get Safe Browsing protection, where available, in other Brave services, like Gmail and Search. + + Does not protect you against dangerous websites, downloads, and extensions. Your Safe Browsing settings in other Brave products won't be affected. + Enhanced protection: + + Enhanced protection + Predicts and warns you about dangerous events before they happen. + + Warns you about dangerous sites, even ones Brave didn’t know about before, by analyzing more data from sites than standard protection. You can choose to skip Brave warnings. + Keeps you safe on Brave and may be used to improve your security in other Brave apps when you are signed in. + + In-depth scans for suspicious downloads. + Improves security for you and everyone on the web. + + When you're signed in, protects you across Brave services. + Warns you if passwords are exposed in a data breach. + + Improves security for you and everyone on the web. + Sends URLs to Safe Browsing to check them. Also sends a small sample of pages, downloads, extension activity, and system information to help discover new threats. Temporarily links this data to your Brave sync chain when you’re signed in, to protect you across Brave apps. + + Warns you if you use a password that has been compromised in a data breach. + + + Sends the URLs of sites you visit and a small sample of page content, downloads, extension activity, and system information to Google Safe Browsing to check if they’re harmful. + + + When you’re signed in, this data is linked to your Brave sync chain to protect you across Brave services, for example increasing protection in Gmail after a security incident. + + + Doesn’t noticeably slow down your browser or device. + + + Learn more about <link>how Brave keeps your data private</link> + @@ -1768,6 +1834,9 @@ Your Brave account may have other forms of browsing history like searches and ac Checks URLs with a list of unsafe sites stored in Brave. If a site tries to steal your password, or when you download a harmful file, Brave may also send URLs, including bits of page content, to Safe Browsing. + + Sends an obfuscated portion of the URL to Brave through a privacy server that hides your IP address. If a site tries to steal your password, or when you download a harmful file, Brave may also send URLs, including bits of page content, to Brave. + Help improve security on the web @@ -2392,9 +2461,6 @@ To change this setting, <resetlink>reset sync

Switched to Private tabs - - Reopen closed tab - Restored %1$sYouTube, tab @@ -2404,9 +2470,6 @@ To change this setting, <resetlink>reset sync

%1$sWelcome to Facebook, tab - - %1$sWelcome to Facebook, tab, selected - Close %1$sBrave tab @@ -2497,10 +2560,7 @@ To change this setting, <resetlink>reset sync

- - Suggested password - - + Use strong password? @@ -2911,7 +2971,7 @@ To change this setting, <resetlink>reset sync

- Download page + Download this page Files that you download appear here @@ -2967,6 +3027,9 @@ To change this setting, <resetlink>reset sync

Explore Offline + + Cannot download file. File format not supported. + @@ -3136,6 +3199,20 @@ To change this setting, <resetlink>reset sync

+ + + Continue without a car profile lock? + + + Opening Brave without a profile lock will remove your your saved passwords and payment methods from the car. Using a profile lock keeps this data secure. + + + Also clear bookmarks, history, and more from this car + + + Delete & continue + + Turn on sync? @@ -3572,7 +3649,7 @@ To change this setting, <resetlink>reset sync

- Share + Share this page Voice search @@ -3829,6 +3906,9 @@ To change this setting, <resetlink>reset sync

Search your bookmarks + + Search + Can’t find that bookmark. Check your spelling or add a new bookmark. @@ -3927,6 +4007,9 @@ To change this setting, <resetlink>reset sync

Sort and view options + + Sort by manual order + Sort by newest @@ -4049,13 +4132,13 @@ To change this setting, <resetlink>reset sync

- Open in Brave + Open in Brave browser Open in Private Brave - - Open in %1$sBrave + + Open in %1$sBrave browser Open in browser @@ -4156,10 +4239,10 @@ To change this setting, <resetlink>reset sync

- Home + Open the home page - Refresh page + Reload this page Stop page loading @@ -4398,6 +4481,12 @@ To change this setting, <resetlink>reset sync

Related Insights + + Page insights back button + + + Page insights Loading Indicator + @@ -4436,9 +4525,15 @@ To change this setting, <resetlink>reset sync

You'll now see stories from %1$sReuters when you open a new tab. Sites you follow are saved in your Brave account. You can manage them in Discover settings. + + You'll now see content from and about %1$sReuters in Following. The sites and searches you follow are saved in your Brave sync chain. You can manage your follows in settings at any time. + Soon, you’ll see stories from %1$sReuters when you open a new tab. Sites you follow are saved in your Brave account. You can manage them in Discover settings. + + Soon, you'll see content from and about %1$sReuters in Following. The sites and searches you follow are saved in your Brave sync chain. You can manage your follows in settings at any time. + Go to Following @@ -5222,10 +5317,6 @@ To change this setting, <resetlink>reset sync

- - Scan - - To share with profiles nearby, let them scan this QR Code @@ -5331,46 +5422,10 @@ To change this setting, <resetlink>reset sync

- - Position QR Code/barcode in this frame. - - - - To scan a QR Code, let Brave use your camera - - - - To scan a QR Code, change your settings so that Brave can use your camera - - - - Continue - - - - To scan a QR Code, use a device with a camera. - - - - The organization that manages your device has turned off your camera. - - - - Can't open your camera. Restart your device and try again. - - - - Can't open your camera. Something went wrong. - - Open Settings - - This QR Code is not a URL: %1$sQR Code Text - - chrome_qrcode_%1$s1582667748515 @@ -5644,7 +5699,7 @@ To change this setting, <resetlink>reset sync

- %1$sClassic template selected + %1$sClassic template selected Select a template for your highlight. @@ -5843,6 +5898,41 @@ To change this setting, <resetlink>reset sync

Please wait… + + + + Tap to close “Listen to this page”. + + + “Listen to this page” player. + + + “Listen to this page” player opened at full height. + + + “Listen to this page” player minimized. + + + Brave now playing + + + Back %1$s10 seconds + + + Forward %1$s30 seconds + + + Play + + + Pause + + + Playback speed: %1$s1.0. Click to change. + + + More options + diff --git a/browser/ui/android/strings/android_chrome_strings_override.grd b/browser/ui/android/strings/android_chrome_strings_override.grd index c414d530021c..59676da0508e 100644 --- a/browser/ui/android/strings/android_chrome_strings_override.grd +++ b/browser/ui/android/strings/android_chrome_strings_override.grd @@ -144,10 +144,13 @@ Based on your interaction with a site, like regularly signing in to an account, Private state tokens improve privacy on the web and can’t be used to find out who you are. - Block while using private + Block while using Private - While in private, sites can’t use your cookies to see your browsing activity across different sites, for example, to personalize ads. Features on some sites may break. + While in Private, sites can’t use your cookies to see your browsing activity across different sites, for example, to personalize ads. Features on some sites may break. + + + When you tap or type in the address bar or search box, you'll see suggestions from your default search engine. This is off in Private. Private tabs diff --git a/browser/ui/browser_commands.cc b/browser/ui/browser_commands.cc index 3643f5b2532c..6d2b1c535d2a 100644 --- a/browser/ui/browser_commands.cc +++ b/browser/ui/browser_commands.cc @@ -33,7 +33,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_tabstrip.h" -#include "chrome/browser/ui/profile_picker.h" +#include "chrome/browser/ui/profiles/profile_picker.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_group.h" #include "chrome/browser/ui/tabs/tab_group_model.h" diff --git a/browser/ui/views/profiles/brave_profile_menu_view.cc b/browser/ui/views/profiles/brave_profile_menu_view.cc index 8675efc05d35..cbdbb5fa1c9f 100644 --- a/browser/ui/views/profiles/brave_profile_menu_view.cc +++ b/browser/ui/views/profiles/brave_profile_menu_view.cc @@ -1,7 +1,7 @@ -/* Copyright 2019 The Brave Authors. All rights reserved. +/* Copyright (c) 2019 The Brave Authors. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "brave/browser/ui/views/profiles/brave_profile_menu_view.h" @@ -16,7 +16,7 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_window.h" #include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/signin/profile_colors_util.h" +#include "chrome/browser/ui/profiles/profile_colors_util.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/grit/generated_resources.h" #include "components/vector_icons/vector_icons.h" diff --git a/browser/ui/views/sidebar/sidebar_container_view.cc b/browser/ui/views/sidebar/sidebar_container_view.cc index 814e2de07dcf..8152b967a9a2 100644 --- a/browser/ui/views/sidebar/sidebar_container_view.cc +++ b/browser/ui/views/sidebar/sidebar_container_view.cc @@ -42,8 +42,8 @@ #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "components/grit/brave_components_strings.h" #include "content/public/browser/browser_context.h" -#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/input/native_web_keyboard_event.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/events/event_observer.h" diff --git a/browser/ui/views/tabs/vertical_tab_utils.cc b/browser/ui/views/tabs/vertical_tab_utils.cc index f67c9f1c38fa..4ef02a867afb 100644 --- a/browser/ui/views/tabs/vertical_tab_utils.cc +++ b/browser/ui/views/tabs/vertical_tab_utils.cc @@ -97,9 +97,9 @@ std::pair GetLeadingTrailingCaptionButtonWidth( if (!using_gtk_caption_button) { auto* window_order_provider = views::WindowButtonOrderProvider::GetInstance(); - return {views::kCaptionButtonWidth * + return {views::GetCaptionButtonWidth() * window_order_provider->leading_buttons().size(), - views::kCaptionButtonWidth * + views::GetCaptionButtonWidth() * window_order_provider->trailing_buttons().size()}; } diff --git a/browser/ui/webui/settings/brave_import_bulk_data_handler.cc b/browser/ui/webui/settings/brave_import_bulk_data_handler.cc index d972c43a19f8..6017d3331766 100644 --- a/browser/ui/webui/settings/brave_import_bulk_data_handler.cc +++ b/browser/ui/webui/settings/brave_import_bulk_data_handler.cc @@ -32,7 +32,7 @@ base::FilePath GetProfilePathByName(const std::u16string& name) { std::vector entries = g_browser_process->profile_manager() ->GetProfileAttributesStorage() - .GetAllProfilesAttributesSortedByName(); + .GetAllProfilesAttributesSortedByNameWithCheck(); for (auto* it : entries) { if (it->GetName() == name) { return it->GetPath(); diff --git a/browser/ui/webui/settings/brave_import_data_handler.cc b/browser/ui/webui/settings/brave_import_data_handler.cc index bb83de088d1d..74a38b46e4a4 100644 --- a/browser/ui/webui/settings/brave_import_data_handler.cc +++ b/browser/ui/webui/settings/brave_import_data_handler.cc @@ -18,9 +18,9 @@ #include "content/public/browser/web_contents.h" #if BUILDFLAG(IS_MAC) +#include "base/apple/foundation_util.h" #include "base/files/file_path.h" #include "base/files/file_util.h" -#include "base/mac/foundation_util.h" #include "base/task/thread_pool.h" #include "brave/browser/ui/webui/settings/brave_full_disk_access_confirm_dialog_delegate.h" #include "chrome/browser/ui/browser_finder.h" @@ -32,7 +32,7 @@ namespace { bool HasProperDiskAccessPermission(uint16_t imported_items) { DCHECK(imported_items); - const base::FilePath& library_dir = base::mac::GetUserLibraryPath(); + const base::FilePath& library_dir = base::apple::GetUserLibraryPath(); const base::FilePath safari_dir = library_dir.Append("Safari"); if (imported_items & importer::FAVORITES) { diff --git a/browser/ui/webui/settings/settings_cookies_view_handler.cc b/browser/ui/webui/settings/settings_cookies_view_handler.cc index 430c6be711f6..d5a6bf80d8f0 100644 --- a/browser/ui/webui/settings/settings_cookies_view_handler.cc +++ b/browser/ui/webui/settings/settings_cookies_view_handler.cc @@ -95,15 +95,13 @@ void CookiesViewHandler::RegisterMessages() { base::Unretained(this))); } -void CookiesViewHandler::TreeNodesAdded(ui::TreeModel* model, - ui::TreeModelNode* parent, - size_t start, - size_t count) {} - -void CookiesViewHandler::TreeNodesRemoved(ui::TreeModel* model, - ui::TreeModelNode* parent, - size_t start, - size_t count) { +void CookiesViewHandler::TreeNodeAdded(ui::TreeModel* model, + ui::TreeModelNode* parent, + size_t index) {} + +void CookiesViewHandler::TreeNodeRemoved(ui::TreeModel* model, + ui::TreeModelNode* parent, + size_t index) { // Skip if there is a batch update in progress. if (batch_update_) { return; diff --git a/browser/ui/webui/settings/settings_cookies_view_handler.h b/browser/ui/webui/settings/settings_cookies_view_handler.h index b092da79345d..f2c6b3030c68 100644 --- a/browser/ui/webui/settings/settings_cookies_view_handler.h +++ b/browser/ui/webui/settings/settings_cookies_view_handler.h @@ -41,16 +41,12 @@ class CookiesViewHandler : public SettingsPageUIHandler, void RegisterMessages() override; // CookiesTreeModel::Observer: - void TreeNodesAdded(ui::TreeModel* model, - ui::TreeModelNode* parent, - size_t start, - size_t count) override; - void TreeNodesRemoved(ui::TreeModel* model, - ui::TreeModelNode* parent, - size_t start, - size_t count) override; - void TreeNodeChanged(ui::TreeModel* model, ui::TreeModelNode* node) override { - } + void TreeNodeAdded(ui::TreeModel* model, + ui::TreeModelNode* parent, + size_t index) override; + void TreeNodeRemoved(ui::TreeModel* model, + ui::TreeModelNode* parent, + size_t index) override; void TreeModelBeginBatchDeprecated(CookiesTreeModel* model) override; void TreeModelEndBatchDeprecated(CookiesTreeModel* model) override; diff --git a/build/android/bytecode/BUILD.gn b/build/android/bytecode/BUILD.gn index 0ca8cb39b0d9..c41dc441f275 100644 --- a/build/android/bytecode/BUILD.gn +++ b/build/android/bytecode/BUILD.gn @@ -41,7 +41,6 @@ java_binary("java_bytecode_rewriter") { "//brave/build/android/bytecode/java/org/brave/bytecode/BraveDropdownItemViewInfoListBuilderClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveDropdownItemViewInfoListManagerClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveDynamicColorsClassAdapter.java", - "//brave/build/android/bytecode/java/org/brave/bytecode/BraveEditUrlSuggestionProcessorClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveExternalNavigationHandlerClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveFeedSurfaceCoordinatorClassAdapter.java", "//brave/build/android/bytecode/java/org/brave/bytecode/BraveFeedSurfaceMediatorClassAdapter.java", diff --git a/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java b/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java index daa00b00e19c..8031e87fde29 100644 --- a/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java +++ b/build/android/bytecode/java/org/brave/bytecode/BraveClassAdapter.java @@ -39,7 +39,6 @@ public static ClassVisitor createAdapter(ClassVisitor chain) { chain = new BraveDropdownItemViewInfoListBuilderClassAdapter(chain); chain = new BraveDropdownItemViewInfoListManagerClassAdapter(chain); chain = new BraveDynamicColorsClassAdapter(chain); - chain = new BraveEditUrlSuggestionProcessorClassAdapter(chain); chain = new BraveExternalNavigationHandlerClassAdapter(chain); chain = new BraveFeedSurfaceCoordinatorClassAdapter(chain); chain = new BraveFeedSurfaceMediatorClassAdapter(chain); diff --git a/build/android/bytecode/java/org/brave/bytecode/BraveEditUrlSuggestionProcessorClassAdapter.java b/build/android/bytecode/java/org/brave/bytecode/BraveEditUrlSuggestionProcessorClassAdapter.java deleted file mode 100644 index 08454b31da0c..000000000000 --- a/build/android/bytecode/java/org/brave/bytecode/BraveEditUrlSuggestionProcessorClassAdapter.java +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (c) 2020 The Brave Authors. All rights reserved. - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at https://mozilla.org/MPL/2.0/. */ - -package org.brave.bytecode; - -import org.objectweb.asm.ClassVisitor; - -public class BraveEditUrlSuggestionProcessorClassAdapter extends BraveClassVisitor { - static String sEditUrlSuggestionProcessor = - "org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionProcessor"; - static String sBraveEditUrlSuggestionProcessor = - "org/chromium/chrome/browser/omnibox/suggestions/editurl/BraveEditUrlSuggestionProcessor"; - - public BraveEditUrlSuggestionProcessorClassAdapter(ClassVisitor visitor) { - super(visitor); - - redirectConstructor(sEditUrlSuggestionProcessor, sBraveEditUrlSuggestionProcessor); - - deleteField(sBraveEditUrlSuggestionProcessor, "mHasClearedOmniboxForFocus"); - makeProtectedField(sEditUrlSuggestionProcessor, "mHasClearedOmniboxForFocus"); - } -} diff --git a/build/android/bytecode/java/org/brave/bytecode/BraveLocationBarMediatorClassAdapter.java b/build/android/bytecode/java/org/brave/bytecode/BraveLocationBarMediatorClassAdapter.java index 7b22bd062476..f0fac86c1fca 100644 --- a/build/android/bytecode/java/org/brave/bytecode/BraveLocationBarMediatorClassAdapter.java +++ b/build/android/bytecode/java/org/brave/bytecode/BraveLocationBarMediatorClassAdapter.java @@ -34,6 +34,8 @@ public BraveLocationBarMediatorClassAdapter(ClassVisitor visitor) { makeProtectedField(sLocationBarMediator, "mIsTablet"); deleteField(sBraveLocationBarMediator, "mIsLocationBarFocusedFromNtpScroll"); makeProtectedField(sLocationBarMediator, "mIsLocationBarFocusedFromNtpScroll"); + deleteField(sBraveLocationBarMediator, "mShouldClearOmniboxOnFocus"); + makeProtectedField(sLocationBarMediator, "mShouldClearOmniboxOnFocus"); deleteField(sBraveLocationBarMediator, "mContext"); makeProtectedField(sLocationBarMediator, "mContext"); deleteField(sBraveLocationBarMediator, "mBrandedColorScheme"); diff --git a/build/commands/lib/config.js b/build/commands/lib/config.js index 5c32af82b495..99aab7993820 100644 --- a/build/commands/lib/config.js +++ b/build/commands/lib/config.js @@ -280,10 +280,6 @@ Config.prototype.isOfficialBuild = function () { return this.isReleaseBuild() && !this.isAsan() } -Config.prototype.getBrandingPathProduct = function () { - return this.isOfficialBuild() ? "brave" : "brave-development" -} - Config.prototype.getBraveLogoIconName = function () { let iconName = "brave-icon-debug-color.svg" if (this.isBraveReleaseBuild()) { @@ -324,7 +320,7 @@ Config.prototype.buildArgs = function () { proprietary_codecs: true, ffmpeg_branding: "Chrome", branding_path_component: "brave", - branding_path_product: this.getBrandingPathProduct(), + branding_path_product: "brave", enable_nacl: false, enable_widevine: true, // Our copy of signature_generator.py doesn't support --ignore_missing_cert: diff --git a/build/commands/lib/util.js b/build/commands/lib/util.js index 7c1b97e62753..df741995088b 100644 --- a/build/commands/lib/util.js +++ b/build/commands/lib/util.js @@ -272,7 +272,8 @@ const util = { // Copy to make our ${branding_path_product}_behaviors.cc fileMap.add([path.join(config.braveCoreDir, 'chromium_src', 'chrome', 'installer', 'setup', 'brave_behaviors.cc'), - path.join(config.srcDir, 'chrome', 'installer', 'setup', config.getBrandingPathProduct() + '_behaviors.cc')]) + path.join(config.srcDir, 'chrome', 'installer', 'setup', + 'brave_behaviors.cc')]) // Replace webui CSS to use our fonts. fileMap.add([path.join(config.braveCoreDir, 'ui', 'webui', 'resources', 'css', 'text_defaults_md.css'), path.join(config.srcDir, 'ui', 'webui', 'resources', 'css', 'text_defaults_md.css')]) diff --git a/chromium_src/chrome/browser/extensions/extension_management.cc b/chromium_src/chrome/browser/extensions/extension_management.cc index 6dee99b27fbf..55c75c145511 100644 --- a/chromium_src/chrome/browser/extensions/extension_management.cc +++ b/chromium_src/chrome/browser/extensions/extension_management.cc @@ -6,7 +6,8 @@ #include "brave/browser/extensions/brave_extension_management.h" #define BRAVE_EXTENSION_MANAGEMENT_FACTORY_BUILD_SERVICE_INSTANCE_FOR \ - return new BraveExtensionManagement(Profile::FromBrowserContext(context)); + return std::make_unique( \ + Profile::FromBrowserContext(context)); #include "src/chrome/browser/extensions/extension_management.cc" #undef BRAVE_EXTENSION_MANAGEMENT_FACTORY_BUILD_SERVICE_INSTANCE_FOR diff --git a/chromium_src/chrome/browser/metrics/google_update_metrics_provider_win.cc b/chromium_src/chrome/browser/metrics/google_update_metrics_provider_win.cc new file mode 100644 index 000000000000..3c1efdfdca95 --- /dev/null +++ b/chromium_src/chrome/browser/metrics/google_update_metrics_provider_win.cc @@ -0,0 +1,20 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "build/build_config.h" + +#include "chrome/install_static/buildflags.h" +#include "chrome/install_static/install_constants.h" + +#if defined(OFFICIAL_BUILD) +#undef BUILDFLAG_INTERNAL_USE_GOOGLE_UPDATE_INTEGRATION +#define BUILDFLAG_INTERNAL_USE_GOOGLE_UPDATE_INTEGRATION() (0) +#endif + +#include "src/chrome/browser/metrics/google_update_metrics_provider_win.cc" + +#if defined(OFFICIAL_BUILD) +#undef BUILDFLAG_INTERNAL_USE_GOOGLE_UPDATE_INTEGRATION +#endif diff --git a/chromium_src/chrome/browser/permissions/permission_manager_factory.cc b/chromium_src/chrome/browser/permissions/permission_manager_factory.cc index 156c2b68b776..81fe9feee122 100644 --- a/chromium_src/chrome/browser/permissions/permission_manager_factory.cc +++ b/chromium_src/chrome/browser/permissions/permission_manager_factory.cc @@ -17,14 +17,16 @@ #define GeolocationPermissionContextDelegate \ BraveGeolocationPermissionContextDelegate -#define BuildServiceInstanceFor BuildServiceInstanceFor_ChromiumImpl +#define BuildServiceInstanceForBrowserContext \ + BuildServiceInstanceForBrowserContext_ChromiumImpl #include "src/chrome/browser/permissions/permission_manager_factory.cc" #undef GeolocationPermissionContextDelegate -#undef BuildServiceInstanceFor +#undef BuildServiceInstanceForBrowserContext -KeyedService* PermissionManagerFactory::BuildServiceInstanceFor( +std::unique_ptr +PermissionManagerFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); auto permission_contexts = CreatePermissionContexts(profile); @@ -50,6 +52,6 @@ KeyedService* PermissionManagerFactory::BuildServiceInstanceFor( } } - return new permissions::BravePermissionManager( + return std::make_unique( profile, std::move(permission_contexts)); } diff --git a/chromium_src/chrome/browser/permissions/permission_manager_factory.h b/chromium_src/chrome/browser/permissions/permission_manager_factory.h index 55c75804f00a..e64a28651566 100644 --- a/chromium_src/chrome/browser/permissions/permission_manager_factory.h +++ b/chromium_src/chrome/browser/permissions/permission_manager_factory.h @@ -17,15 +17,15 @@ namespace permissions { class BraveWalletPermissionContextUnitTest; } -#define BuildServiceInstanceFor \ - BuildServiceInstanceFor_ChromiumImpl(content::BrowserContext* profile) \ - const; \ - friend brave_wallet::EthereumProviderImplUnitTest; \ - friend brave_wallet::SolanaProviderImplUnitTest; \ - friend permissions::BraveWalletPermissionContextUnitTest; \ - KeyedService* BuildServiceInstanceFor +#define BuildServiceInstanceForBrowserContext \ + BuildServiceInstanceForBrowserContext_ChromiumImpl( \ + content::BrowserContext* profile) const; \ + friend brave_wallet::EthereumProviderImplUnitTest; \ + friend brave_wallet::SolanaProviderImplUnitTest; \ + friend permissions::BraveWalletPermissionContextUnitTest; \ + std::unique_ptr BuildServiceInstanceForBrowserContext #include "src/chrome/browser/permissions/permission_manager_factory.h" // IWYU pragma: export -#undef BuildServiceInstanceFor +#undef BuildServiceInstanceForBrowserContext #endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_PERMISSIONS_PERMISSION_MANAGER_FACTORY_H_ diff --git a/chromium_src/chrome/browser/preloading/preloading_features.cc b/chromium_src/chrome/browser/preloading/preloading_features.cc new file mode 100644 index 000000000000..51dde59d1252 --- /dev/null +++ b/chromium_src/chrome/browser/preloading/preloading_features.cc @@ -0,0 +1,16 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "src/chrome/browser/preloading/preloading_features.cc" + +#include "base/feature_override.h" + +namespace features { + +OVERRIDE_FEATURE_DEFAULT_STATES({{ + {kPerformanceSettingsPreloadingSubpage, base::FEATURE_DISABLED_BY_DEFAULT}, +}}); + +} // namespace features diff --git a/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc b/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc index 2829c8b1f587..9eca51e7a657 100644 --- a/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc +++ b/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc @@ -7,15 +7,17 @@ #include "brave/components/privacy_sandbox/brave_privacy_sandbox_settings.h" -#define BuildServiceInstanceFor BuildServiceInstanceFor_ChromiumImpl +#define BuildServiceInstanceForBrowserContext \ + BuildServiceInstanceForBrowserContext_ChromiumImpl #include "src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.cc" -#undef BuildServiceInstanceFor +#undef BuildServiceInstanceForBrowserContext -KeyedService* PrivacySandboxSettingsFactory::BuildServiceInstanceFor( +std::unique_ptr +PrivacySandboxSettingsFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); - return new BravePrivacySandboxSettings( + return std::make_unique( std::make_unique(profile), HostContentSettingsMapFactory::GetForProfile(profile), CookieSettingsFactory::GetForProfile(profile).get(), profile->GetPrefs()); diff --git a/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h b/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h index 4a241e3fb6ef..c21fffcfe225 100644 --- a/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h +++ b/chromium_src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h @@ -8,12 +8,13 @@ #include "components/keyed_service/content/browser_context_keyed_service_factory.h" -#define BuildServiceInstanceFor \ - BuildServiceInstanceFor_ChromiumImpl(content::BrowserContext*) const; \ - KeyedService* BuildServiceInstanceFor +#define BuildServiceInstanceForBrowserContext \ + BuildServiceInstanceForBrowserContext_ChromiumImpl(content::BrowserContext*) \ + const; \ + std::unique_ptr BuildServiceInstanceForBrowserContext #include "src/chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h" // IWYU pragma: export -#undef BuildServiceInstanceFor +#undef BuildServiceInstanceForBrowserContext #endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SETTINGS_FACTORY_H_ diff --git a/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.cc b/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.cc index 89fb5ade919b..cd51c90320bb 100644 --- a/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.cc +++ b/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.cc @@ -5,14 +5,16 @@ #include "chrome/browser/profiles/gaia_info_update_service_factory.h" -// Include to prevent redefining BuildServiceInstanceFor +// Include to prevent redefining BuildServiceInstanceForBrowserContext #include "chrome/browser/signin/identity_manager_factory.h" -#define BuildServiceInstanceFor BuildServiceInstanceFor_ChromiumImpl +#define BuildServiceInstanceForBrowserContext \ + BuildServiceInstanceForBrowserContext_ChromiumImpl #include "src/chrome/browser/profiles/gaia_info_update_service_factory.cc" -#undef BuildServiceInstanceFor +#undef BuildServiceInstanceForBrowserContext -KeyedService* GAIAInfoUpdateServiceFactory::BuildServiceInstanceFor( +std::unique_ptr +GAIAInfoUpdateServiceFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { return nullptr; } diff --git a/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.h b/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.h index b5ac52c1dcb5..95931e61da70 100644 --- a/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.h +++ b/chromium_src/chrome/browser/profiles/gaia_info_update_service_factory.h @@ -6,15 +6,15 @@ #ifndef BRAVE_CHROMIUM_SRC_CHROME_BROWSER_PROFILES_GAIA_INFO_UPDATE_SERVICE_FACTORY_H_ #define BRAVE_CHROMIUM_SRC_CHROME_BROWSER_PROFILES_GAIA_INFO_UPDATE_SERVICE_FACTORY_H_ -// Include to prevent redefining BuildServiceInstanceFor +// Include to prevent redefining BuildServiceInstanceForBrowserContext #include "components/keyed_service/content/browser_context_keyed_service_factory.h" -#define BuildServiceInstanceFor \ - BuildServiceInstanceFor_ChromiumImpl(content::BrowserContext* context) \ - const; \ - KeyedService* BuildServiceInstanceFor +#define BuildServiceInstanceForBrowserContext \ + BuildServiceInstanceForBrowserContext_ChromiumImpl( \ + content::BrowserContext* context) const; \ + std::unique_ptr BuildServiceInstanceForBrowserContext #include "src/chrome/browser/profiles/gaia_info_update_service_factory.h" // IWYU pragma: export -#undef BuildServiceInstanceFor +#undef BuildServiceInstanceForBrowserContext #endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_PROFILES_GAIA_INFO_UPDATE_SERVICE_FACTORY_H_ diff --git a/chromium_src/chrome/browser/profiles/pref_service_builder_utils.cc b/chromium_src/chrome/browser/profiles/pref_service_builder_utils.cc index 7005efa469bc..207a65a0d1fa 100644 --- a/chromium_src/chrome/browser/profiles/pref_service_builder_utils.cc +++ b/chromium_src/chrome/browser/profiles/pref_service_builder_utils.cc @@ -36,8 +36,6 @@ void RegisterProfilePrefs(bool is_signin_profile, base::Value(false)); #if BUILDFLAG(IS_LINUX) // Use brave theme by default instead of gtk theme. - registry->SetDefaultPrefValue(prefs::kUsesSystemThemeDeprecated, - base::Value(false)); registry->SetDefaultPrefValue( prefs::kSystemTheme, base::Value(static_cast(ui::SystemTheme::kDefault))); diff --git a/chromium_src/chrome/browser/search_engines/template_url_service_factory.h b/chromium_src/chrome/browser/search_engines/template_url_service_factory.h index 129605b1bbe3..0a329e03a64d 100644 --- a/chromium_src/chrome/browser/search_engines/template_url_service_factory.h +++ b/chromium_src/chrome/browser/search_engines/template_url_service_factory.h @@ -1,7 +1,7 @@ -/* Copyright 2021 The Brave Authors. All rights reserved. +/* Copyright (c) 2021 The Brave Authors. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * You can obtain one at https://mozilla.org/MPL/2.0/. */ #ifndef BRAVE_CHROMIUM_SRC_CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_FACTORY_H_ #define BRAVE_CHROMIUM_SRC_CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_FACTORY_H_ @@ -10,14 +10,14 @@ #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "content/public/browser/browser_context.h" -#define BuildServiceInstanceFor \ - BuildServiceInstanceFor_unused(); \ +#define BrowserContextDestroyed \ + BrowserContextDestroyed_unused(); \ content::BrowserContext* GetBrowserContextToUse( \ content::BrowserContext* context) const override; \ - KeyedService* BuildServiceInstanceFor + void BrowserContextDestroyed #include "src/chrome/browser/search_engines/template_url_service_factory.h" // IWYU pragma: export -#undef BuildServiceInstanceFor +#undef BrowserContextDestroyed #endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_FACTORY_H_ diff --git a/chromium_src/chrome/browser/shell_integration_mac.mm b/chromium_src/chrome/browser/shell_integration_mac.mm index 6a094770e1a3..9f999b0e5068 100644 --- a/chromium_src/chrome/browser/shell_integration_mac.mm +++ b/chromium_src/chrome/browser/shell_integration_mac.mm @@ -6,9 +6,9 @@ #include "chrome/browser/shell_integration.h" #include "base/apple/bundle_locations.h" -#include "base/mac/foundation_util.h" +#include "base/apple/foundation_util.h" +#include "base/apple/scoped_cftyperef.h" #include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" #include "build/branding_buildflags.h" #include "chrome/common/channel_info.h" diff --git a/chromium_src/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chromium_src/chrome/browser/ui/autofill/chrome_autofill_client.cc index 7fd4caf3d60c..84b518406562 100644 --- a/chromium_src/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chromium_src/chrome/browser/ui/autofill/chrome_autofill_client.cc @@ -9,6 +9,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/autofill/payments/webauthn_dialog_controller_impl.h" #include "chrome/browser/ui/page_info/page_info_dialog.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" namespace autofill { diff --git a/chromium_src/chrome/browser/ui/color/win/native_chrome_color_mixer_win.cc b/chromium_src/chrome/browser/ui/color/win/native_chrome_color_mixer_win.cc index cf0cc80fe43e..43efd3aaf9a9 100644 --- a/chromium_src/chrome/browser/ui/color/win/native_chrome_color_mixer_win.cc +++ b/chromium_src/chrome/browser/ui/color/win/native_chrome_color_mixer_win.cc @@ -32,6 +32,7 @@ class FakeAccentColorObserver { return absl::nullopt; } absl::optional accent_border_color() const { return absl::nullopt; } + bool use_dwm_frame_color() const { return false; } private: base::RepeatingClosureList callbacks_; diff --git a/chromium_src/chrome/browser/ui/views/frame/browser_frame.h b/chromium_src/chrome/browser/ui/views/frame/browser_frame.h index 265fa904e410..03892434c271 100644 --- a/chromium_src/chrome/browser/ui/views/frame/browser_frame.h +++ b/chromium_src/chrome/browser/ui/views/frame/browser_frame.h @@ -6,13 +6,13 @@ #ifndef BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_H_ #define BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_H_ -#define SelectNativeTheme \ - SelectNativeTheme_Unused() {} \ +#define OnMenuClosed \ + OnMenuClosed_Unused() {} \ friend class BraveBrowserFrame; \ - void SelectNativeTheme + void OnMenuClosed #include "src/chrome/browser/ui/views/frame/browser_frame.h" // IWYU pragma: export -#undef SelectNativeTheme +#undef OnMenuClosed #endif // BRAVE_CHROMIUM_SRC_CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_FRAME_H_ diff --git a/chromium_src/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chromium_src/chrome/browser/ui/views/frame/browser_view_browsertest.cc new file mode 100644 index 000000000000..a3ec371ee493 --- /dev/null +++ b/chromium_src/chrome/browser/ui/views/frame/browser_view_browsertest.cc @@ -0,0 +1,12 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/views/side_panel/brave_side_panel.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/side_panel/side_panel.h" + +#define SidePanel BraveSidePanel +#include "src/chrome/browser/ui/views/frame/browser_view_browsertest.cc" +#undef SidePanel diff --git a/chromium_src/chrome/browser/ui/views/page_info/page_info_main_view.cc b/chromium_src/chrome/browser/ui/views/page_info/page_info_main_view.cc index 0ab4db23f1d7..db15aadeed46 100644 --- a/chromium_src/chrome/browser/ui/views/page_info/page_info_main_view.cc +++ b/chromium_src/chrome/browser/ui/views/page_info/page_info_main_view.cc @@ -28,13 +28,7 @@ const ui::ImageModel GetIpfsGetConnectionSecureIcon() { GetConnectionSecureIcon() != ui::ImageModel() && IsIPFSPage(presenter_) \ ? GetIpfsGetConnectionSecureIcon() \ : PageInfoViewFactory::GetConnectionSecureIcon -#define BRAVE_PAGE_INFO_MAIN_VIEW_CALCULATE_PREFERRED_SIZE \ - if (IsIPFSPage(presenter_)) { \ - width = \ - std::max(security_container_view_->GetPreferredSize().width(), width); \ - } #include "src/chrome/browser/ui/views/page_info/page_info_main_view.cc" -#undef BRAVE_PAGE_INFO_MAIN_VIEW_CALCULATE_PREFERRED_SIZE #undef GetConnectionSecureIcon diff --git a/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.cc b/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.cc index bd78646c6f6e..f753ea140b86 100644 --- a/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.cc +++ b/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.cc @@ -50,8 +50,10 @@ SkPath TabGroupStyle::GetUnderlinePath(gfx::Rect local_bounds) const { return path; } -gfx::Insets TabGroupStyle::GetInsetsForHeaderChip() const { - auto insets = TabGroupStyle_ChromiumImpl::GetInsetsForHeaderChip(); +gfx::Insets TabGroupStyle::GetInsetsForHeaderChip( + bool should_show_sync_icon) const { + auto insets = + TabGroupStyle_ChromiumImpl::GetInsetsForHeaderChip(should_show_sync_icon); if (!tabs::features::HorizontalTabsUpdateEnabled()) { return insets; } diff --git a/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.h b/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.h index 432645d836be..154075a97bf5 100644 --- a/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.h +++ b/chromium_src/chrome/browser/ui/views/tabs/tab_group_style.h @@ -22,7 +22,7 @@ class TabGroupStyle : public TabGroupStyle_ChromiumImpl { SkPath GetUnderlinePath(gfx::Rect local_bounds) const override; - gfx::Insets GetInsetsForHeaderChip() const override; + gfx::Insets GetInsetsForHeaderChip(bool should_show_sync_icon) const override; float GetEmptyChipSize() const override; diff --git a/chromium_src/chrome/browser/ui/webui/help/version_updater_mac.mm b/chromium_src/chrome/browser/ui/webui/help/version_updater_mac.mm index 74bc108f0847..d8c8e210615f 100644 --- a/chromium_src/chrome/browser/ui/webui/help/version_updater_mac.mm +++ b/chromium_src/chrome/browser/ui/webui/help/version_updater_mac.mm @@ -5,7 +5,7 @@ #include "chrome/browser/ui/webui/help/version_updater_mac.h" -#include "base/mac/foundation_util.h" +#include "base/apple/foundation_util.h" #include "base/memory/raw_ptr.h" #include "base/strings/escape.h" #include "base/strings/sys_string_conversions.h" @@ -122,11 +122,11 @@ - (void)handleStatusNotification:(NSNotification*)notification { } void VersionUpdaterMac::UpdateStatus(NSDictionary* dictionary) { - AutoupdateStatus sparkle_status = static_cast( - [base::mac::ObjCCastStrict( + AutoupdateStatus sparkle_status = + static_cast([base::apple::ObjCCastStrict( [dictionary objectForKey:kAutoupdateStatusStatus]) intValue]); - std::string error_messages = base::SysNSStringToUTF8( - base::mac::ObjCCastStrict( + std::string error_messages = + base::SysNSStringToUTF8(base::apple::ObjCCastStrict( [dictionary objectForKey:kAutoupdateStatusErrorMessages])); std::u16string message; diff --git a/chromium_src/chrome/browser/ui/webui/webui_util.cc b/chromium_src/chrome/browser/ui/webui/webui_util.cc index ddc1ced9b5e7..52ce3e5a7e48 100644 --- a/chromium_src/chrome/browser/ui/webui/webui_util.cc +++ b/chromium_src/chrome/browser/ui/webui/webui_util.cc @@ -28,13 +28,11 @@ bool IsChromeUntrustedDataSource(content::WebUIDataSource* source) { } constexpr char kBraveCSP[] = - "script-src chrome://resources " - "chrome://test " + "script-src chrome://resources chrome://webui-test " "'self';"; constexpr char kBraveUntrustedCSP[] = "script-src chrome-untrusted://resources " - "chrome://test " "'self';"; } // namespace diff --git a/chromium_src/chrome/common/chrome_features.cc b/chromium_src/chrome/common/chrome_features.cc index 1670ee957663..f1567add3646 100644 --- a/chromium_src/chrome/common/chrome_features.cc +++ b/chromium_src/chrome/common/chrome_features.cc @@ -18,12 +18,16 @@ OVERRIDE_FEATURE_DEFAULT_STATES({{ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) {kDesktopPWAsLinkCapturing, base::FEATURE_DISABLED_BY_DEFAULT}, #endif + {kPrivacyGuide3, base::FEATURE_DISABLED_BY_DEFAULT}, #if BUILDFLAG(IS_ANDROID) {kPrivacyGuideAndroidPostMVP, base::FEATURE_DISABLED_BY_DEFAULT}, +#endif + {kPrivacyGuidePreload, base::FEATURE_DISABLED_BY_DEFAULT}, +#if BUILDFLAG(IS_ANDROID) + {kPrivacyGuidePreloadAndroid, base::FEATURE_DISABLED_BY_DEFAULT}, #endif {kSCTAuditing, base::FEATURE_DISABLED_BY_DEFAULT}, #if !BUILDFLAG(IS_ANDROID) - {kPrivacyGuide3, base::FEATURE_DISABLED_BY_DEFAULT}, {kTrustSafetySentimentSurvey, base::FEATURE_DISABLED_BY_DEFAULT}, {kTrustSafetySentimentSurveyV2, base::FEATURE_DISABLED_BY_DEFAULT}, #endif diff --git a/chromium_src/chrome/common/url_constants.cc b/chromium_src/chrome/common/url_constants.cc index 731d6a068d8a..149d3ec91734 100644 --- a/chromium_src/chrome/common/url_constants.cc +++ b/chromium_src/chrome/common/url_constants.cc @@ -196,6 +196,10 @@ const char kSafeBrowsingHelpCenterURL[] = "https://support.brave.com/hc/en-us/articles/" "15222663599629-Safe-Browsing-in-Brave"; +const char kSafeBrowsingHelpCenterUpdatedURL[] = "https://support.brave.com/"; + +const char kSafeBrowsingInChromeHelpCenterURL[] = "https://support.brave.com/"; + const char kSafetyTipHelpCenterURL[] = "https://support.brave.com/hc/en-us/articles/17550072876045-Lookalike-URLs"; diff --git a/chromium_src/chrome/tools/build/win/create_installer_archive.py b/chromium_src/chrome/tools/build/win/create_installer_archive.py index 302adbb0ae64..cc28a59894f1 100644 --- a/chromium_src/chrome/tools/build/win/create_installer_archive.py +++ b/chromium_src/chrome/tools/build/win/create_installer_archive.py @@ -22,11 +22,11 @@ @override_utils.override_function(globals()) def CopyAllFilesToStagingDir(original_function, config, distribution, staging_dir, build_dir, enable_hidpi, - include_snapshotblob, component_build, + include_snapshotblob, include_dxc, component_build, component_ffmpeg_build, verbose): original_function(config, distribution, staging_dir, build_dir, - enable_hidpi, include_snapshotblob, component_build, - component_ffmpeg_build, verbose) + enable_hidpi, include_snapshotblob, include_dxc, + component_build, component_ffmpeg_build, verbose) brave_extension_locales_src_dir_path = os.path.realpath( os.path.join(get_src_dir(), 'brave', 'components', 'brave_extension', 'extension', 'brave_extension', '_locales')) diff --git a/chromium_src/components/autofill/core/browser/autofill_experiments.cc b/chromium_src/components/autofill/core/browser/autofill_experiments.cc index 469dedf35b5c..a6b0a952da07 100644 --- a/chromium_src/components/autofill/core/browser/autofill_experiments.cc +++ b/chromium_src/components/autofill/core/browser/autofill_experiments.cc @@ -5,7 +5,7 @@ #include -#include "components/autofill/core/browser/sync_utils.h" +#include "components/autofill/core/browser/metrics/autofill_metrics.h" class PrefService; namespace syncer { @@ -15,11 +15,12 @@ class SyncService; namespace autofill { class LogManager; class PersonalDataManager; -bool IsCreditCardUploadEnabled(const syncer::SyncService* sync_service, - const std::string& user_email, - const std::string& user_country, - const AutofillSyncSigninState sync_state, - LogManager* log_manager) { +bool IsCreditCardUploadEnabled( + const syncer::SyncService* sync_service, + const std::string& user_email, + const std::string& user_country, + AutofillMetrics::PaymentsSigninState signin_state_for_metrics, + LogManager* log_manager) { return false; } bool IsCreditCardMigrationEnabled(PersonalDataManager* personal_data_manager, diff --git a/chromium_src/components/autofill/core/browser/autofill_experiments_unittest.cc b/chromium_src/components/autofill/core/browser/autofill_experiments_unittest.cc index 5f01415f04b9..f4ac212ca618 100644 --- a/chromium_src/components/autofill/core/browser/autofill_experiments_unittest.cc +++ b/chromium_src/components/autofill/core/browser/autofill_experiments_unittest.cc @@ -29,21 +29,26 @@ class AutofillExperimentsTest : public testing::Test { log_manager_ = LogManager::Create(nullptr, base::RepeatingClosure()); } - bool IsCreditCardUploadEnabled(const AutofillSyncSigninState sync_state) { - return IsCreditCardUploadEnabled("john.smith@gmail.com", sync_state); + bool IsCreditCardUploadEnabled( + const AutofillMetrics::PaymentsSigninState signin_state_for_metrics) { + return IsCreditCardUploadEnabled("john.smith@gmail.com", + signin_state_for_metrics); } - bool IsCreditCardUploadEnabled(const std::string& user_email, - const AutofillSyncSigninState sync_state) { - return IsCreditCardUploadEnabled(user_email, "US", sync_state); + bool IsCreditCardUploadEnabled( + const std::string& user_email, + const AutofillMetrics::PaymentsSigninState signin_state_for_metrics) { + return IsCreditCardUploadEnabled(user_email, "US", + signin_state_for_metrics); } - bool IsCreditCardUploadEnabled(const std::string& user_email, - const std::string& user_country, - const AutofillSyncSigninState sync_state) { - return autofill::IsCreditCardUploadEnabled(&sync_service_, user_email, - user_country, sync_state, - log_manager_.get()); + bool IsCreditCardUploadEnabled( + const std::string& user_email, + const std::string& user_country, + const AutofillMetrics::PaymentsSigninState signin_state_for_metrics) { + return autofill::IsCreditCardUploadEnabled( + &sync_service_, user_email, user_country, signin_state_for_metrics, + log_manager_.get()); } base::test::ScopedFeatureList scoped_feature_list_; @@ -55,13 +60,13 @@ class AutofillExperimentsTest : public testing::Test { TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_FeatureEnabled) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); EXPECT_FALSE(IsCreditCardUploadEnabled( - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); } TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_FeatureDisabled) { scoped_feature_list_.InitAndDisableFeature(features::kAutofillUpstream); EXPECT_FALSE(IsCreditCardUploadEnabled( - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); } TEST_F( @@ -83,23 +88,23 @@ TEST_F( sync_service_.SetFailedDataTypes({syncer::AUTOFILL_PROFILE}); EXPECT_FALSE(IsCreditCardUploadEnabled( - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); } TEST_F(AutofillExperimentsTest, IsCardUploadEnabled_UserEmailWithGoogleDomain) { scoped_feature_list_.InitAndEnableFeature(features::kAutofillUpstream); EXPECT_FALSE(IsCreditCardUploadEnabled( "john.smith@gmail.com", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); EXPECT_FALSE(IsCreditCardUploadEnabled( "googler@google.com", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); EXPECT_FALSE(IsCreditCardUploadEnabled( "old.school@googlemail.com", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); EXPECT_FALSE(IsCreditCardUploadEnabled( "code.committer@chromium.org", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); } TEST_F(AutofillExperimentsTest, @@ -110,16 +115,16 @@ TEST_F(AutofillExperimentsTest, {}); EXPECT_FALSE(IsCreditCardUploadEnabled( "cool.user@hotmail.com", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); EXPECT_FALSE(IsCreditCardUploadEnabled( "john.smith@johnsmith.com", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); EXPECT_FALSE(IsCreditCardUploadEnabled( "fake.googler@google.net", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); EXPECT_FALSE(IsCreditCardUploadEnabled( "fake.committer@chromium.com", - AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled)); + AutofillMetrics::PaymentsSigninState::kSignedInAndSyncFeatureEnabled)); } } // namespace autofill diff --git a/chromium_src/components/browser_ui/site_settings/android/website_preference_bridge.cc b/chromium_src/components/browser_ui/site_settings/android/website_preference_bridge.cc index 45341433f5a0..ca29c04a9787 100644 --- a/chromium_src/components/browser_ui/site_settings/android/website_preference_bridge.cc +++ b/chromium_src/components/browser_ui/site_settings/android/website_preference_bridge.cc @@ -5,6 +5,7 @@ #include "components/content_settings/core/common/content_settings_types.h" #include "components/permissions/permission_manager.h" +#include "third_party/blink/public/common/permissions/permission_utils.h" // Default is ALLOW #define BACKGROUND_SYNC \ diff --git a/chromium_src/components/content_settings/core/common/cookie_settings_base.cc b/chromium_src/components/content_settings/core/common/cookie_settings_base.cc index 415f805fc6fb..d6a163903113 100644 --- a/chromium_src/components/content_settings/core/common/cookie_settings_base.cc +++ b/chromium_src/components/content_settings/core/common/cookie_settings_base.cc @@ -123,8 +123,9 @@ bool CookieSettingsBase::ShouldUseEphemeralStorage( net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) return false; - bool allow_3p = IsCookieAccessAllowedImpl(url, site_for_cookies, - top_frame_origin, overrides); + bool allow_3p = + IsCookieAccessAllowedImpl(url, site_for_cookies, top_frame_origin, + overrides, /*cookie_settings*/ nullptr); bool allow_1p = first_party_setting ? IsAllowed(first_party_setting->setting) : IsFirstPartyAccessAllowed( first_party_url, this, overrides); @@ -144,25 +145,27 @@ bool CookieSettingsBase::IsEphemeralCookieAccessAllowed( } return IsCookieAccessAllowedImpl(url, site_for_cookies, top_frame_origin, - overrides); + overrides, /*cookie_settings*/ nullptr); } bool CookieSettingsBase::IsFullCookieAccessAllowed( const GURL& url, const net::SiteForCookies& site_for_cookies, const absl::optional& top_frame_origin, - net::CookieSettingOverrides overrides) const { + net::CookieSettingOverrides overrides, + CookieSettingWithMetadata* cookie_settings) const { return IsCookieAccessAllowedImpl(url, site_for_cookies, top_frame_origin, - overrides); + overrides, cookie_settings); } bool CookieSettingsBase::IsCookieAccessAllowedImpl( const GURL& url, const net::SiteForCookies& site_for_cookies, const absl::optional& top_frame_origin, - net::CookieSettingOverrides overrides) const { - bool allow = IsChromiumFullCookieAccessAllowed(url, site_for_cookies, - top_frame_origin, overrides); + net::CookieSettingOverrides overrides, + CookieSettingWithMetadata* cookie_settings) const { + bool allow = IsChromiumFullCookieAccessAllowed( + url, site_for_cookies, top_frame_origin, overrides, cookie_settings); const bool is_1p_ephemeral_feature_enabled = base::FeatureList::IsEnabled( net::features::kBraveFirstPartyEphemeralStorage); diff --git a/chromium_src/components/content_settings/core/common/cookie_settings_base.h b/chromium_src/components/content_settings/core/common/cookie_settings_base.h index ff8b10d26e0a..95b82037369a 100644 --- a/chromium_src/components/content_settings/core/common/cookie_settings_base.h +++ b/chromium_src/components/content_settings/core/common/cookie_settings_base.h @@ -44,7 +44,8 @@ struct CookieSettingWithBraveMetadata { bool IsChromiumFullCookieAccessAllowed( \ const GURL& url, const net::SiteForCookies& site_for_cookies, \ const absl::optional& top_frame_origin, \ - net::CookieSettingOverrides overrides) const; \ + net::CookieSettingOverrides overrides, \ + CookieSettingWithMetadata* cookie_settings) const; \ bool ShouldBlockThirdPartyIfSettingIsExplicit( \ bool block_third_party_cookies, ContentSetting cookie_setting, \ bool is_explicit_setting, bool is_first_party_allowed_scheme) const; \ @@ -58,7 +59,8 @@ struct CookieSettingWithBraveMetadata { bool IsCookieAccessAllowedImpl( \ const GURL& url, const net::SiteForCookies& site_for_cookies, \ const absl::optional& top_frame_origin, \ - net::CookieSettingOverrides overrides) const; \ + net::CookieSettingOverrides overrides, \ + CookieSettingWithMetadata* cookie_settings) const; \ \ public: \ bool IsCookieSessionOnly diff --git a/chromium_src/components/content_settings/core/common/features.cc b/chromium_src/components/content_settings/core/common/features.cc index 60bb2d9f0651..327c22b19b0c 100644 --- a/chromium_src/components/content_settings/core/common/features.cc +++ b/chromium_src/components/content_settings/core/common/features.cc @@ -11,6 +11,8 @@ namespace content_settings { namespace features { OVERRIDE_FEATURE_DEFAULT_STATES({{ + {kThirdPartyCookieDeprecationCookieSettings, + base::FEATURE_DISABLED_BY_DEFAULT}, {kUserBypassUI, base::FEATURE_DISABLED_BY_DEFAULT}, }}); diff --git a/chromium_src/components/history_clusters/core/features.cc b/chromium_src/components/history_clusters/core/features.cc index 18907c8c211b..d8dc01dad859 100644 --- a/chromium_src/components/history_clusters/core/features.cc +++ b/chromium_src/components/history_clusters/core/features.cc @@ -21,6 +21,7 @@ OVERRIDE_FEATURE_DEFAULT_STATES({{ {kOmniboxHistoryClusterProvider, base::FEATURE_DISABLED_BY_DEFAULT}, {kPersistedClusters, base::FEATURE_DISABLED_BY_DEFAULT}, {kPersistContextAnnotationsInHistoryDb, base::FEATURE_DISABLED_BY_DEFAULT}, + {kRenameJourneys, base::FEATURE_DISABLED_BY_DEFAULT}, {kSidePanelJourneys, base::FEATURE_DISABLED_BY_DEFAULT}, }}); } // namespace history_clusters::internal diff --git a/chromium_src/components/omnibox/browser/location_bar_model_util.cc b/chromium_src/components/omnibox/browser/location_bar_model_util.cc index b9fa8322d71b..715c86d2e059 100644 --- a/chromium_src/components/omnibox/browser/location_bar_model_util.cc +++ b/chromium_src/components/omnibox/browser/location_bar_model_util.cc @@ -15,13 +15,15 @@ namespace location_bar_model { const gfx::VectorIcon& GetSecurityVectorIcon( security_state::SecurityLevel security_level, - bool use_updated_connection_security_indicators) { + bool use_updated_connection_security_indicators, + security_state::MaliciousContentStatus malicious_content_status) { if (security_level == security_state::SECURE) { return kLeoTuneSmallIcon; } return GetSecurityVectorIcon_Chromium( - security_level, use_updated_connection_security_indicators); + security_level, use_updated_connection_security_indicators, + malicious_content_status); } } // namespace location_bar_model diff --git a/chromium_src/components/optimization_guide/core/optimization_guide_features.cc b/chromium_src/components/optimization_guide/core/optimization_guide_features.cc index 2890de214d3f..26dcc349d81d 100644 --- a/chromium_src/components/optimization_guide/core/optimization_guide_features.cc +++ b/chromium_src/components/optimization_guide/core/optimization_guide_features.cc @@ -11,11 +11,12 @@ namespace optimization_guide { namespace features { OVERRIDE_FEATURE_DEFAULT_STATES({{ + {kOptimizationGuideFetchingForSRP, base::FEATURE_DISABLED_BY_DEFAULT}, {kOptimizationHints, base::FEATURE_DISABLED_BY_DEFAULT}, {kRemoteOptimizationGuideFetching, base::FEATURE_DISABLED_BY_DEFAULT}, {kRemoteOptimizationGuideFetchingAnonymousDataConsent, base::FEATURE_DISABLED_BY_DEFAULT}, - {kOptimizationGuideFetchingForSRP, base::FEATURE_DISABLED_BY_DEFAULT}, + {kTextEmbeddingPageContentAnnotations, base::FEATURE_DISABLED_BY_DEFAULT}, }}); } // namespace features diff --git a/chromium_src/components/permissions/permission_context_base.cc b/chromium_src/components/permissions/permission_context_base.cc index 75fdef1e341c..ec6743910db3 100644 --- a/chromium_src/components/permissions/permission_context_base.cc +++ b/chromium_src/components/permissions/permission_context_base.cc @@ -109,14 +109,11 @@ void PermissionContextBase::PermissionDecided(const PermissionRequestID& id, } void PermissionContextBase::DecidePermission( - const PermissionRequestID& id, - const GURL& requesting_origin, - const GURL& embedding_origin, - bool user_gesture, + permissions::PermissionRequestData request_data, BrowserPermissionCallback callback) { - PermissionContextBase_ChromiumImpl::DecidePermission( - id, requesting_origin, embedding_origin, user_gesture, - std::move(callback)); + auto id = request_data.id; + PermissionContextBase_ChromiumImpl::DecidePermission(std::move(request_data), + std::move(callback)); if (!IsGroupedPermissionType(content_settings_type())) { return; diff --git a/chromium_src/components/permissions/permission_context_base.h b/chromium_src/components/permissions/permission_context_base.h index 342eb6d87e43..1e14b075f1f7 100644 --- a/chromium_src/components/permissions/permission_context_base.h +++ b/chromium_src/components/permissions/permission_context_base.h @@ -49,10 +49,7 @@ class PermissionContextBase : public PermissionContextBase_ChromiumImpl { const base::RepeatingCallback< PermissionLifetimeManager*(content::BrowserContext*)>& factory); - void DecidePermission(const PermissionRequestID& id, - const GURL& requesting_origin, - const GURL& embedding_origin, - bool user_gesture, + void DecidePermission(permissions::PermissionRequestData request_data, BrowserPermissionCallback callback) override; bool IsPendingGroupedRequestsEmptyForTesting(); diff --git a/chromium_src/components/permissions/permission_manager.cc b/chromium_src/components/permissions/permission_manager.cc index bd08baaf553a..e96f46541f3f 100644 --- a/chromium_src/components/permissions/permission_manager.cc +++ b/chromium_src/components/permissions/permission_manager.cc @@ -3,9 +3,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#define BRAVE_FORCED_REQUESTING_ORIGIN \ +#define BRAVE_GET_PERMISSION_RESULT_FOR_CURRENT_DOCUMENT \ !forced_requesting_origin_.is_empty() ? forced_requesting_origin_: +#define BRAVE_REQUEST_PERMISSION_FROM_CURRENT_DOCUMENT \ + if (!forced_requesting_origin_.is_empty()) { \ + auto desc = std::move(request_description); \ + desc.requesting_origin = forced_requesting_origin_; \ + RequestPermissionsInternal(render_frame_host, desc, \ + std::move(permission_status_callback)); \ + return; \ + } + #include "src/components/permissions/permission_manager.cc" -#undef BRAVE_FORCED_REQUESTING_ORIGIN +#undef BRAVE_GET_PERMISSION_RESULT_FOR_CURRENT_DOCUMENT +#undef BRAVE_REQUEST_PERMISSION_FROM_CURRENT_DOCUMENT diff --git a/chromium_src/components/permissions/permission_request.cc b/chromium_src/components/permissions/permission_request.cc index ad05ebeae250..b6a6f810a973 100644 --- a/chromium_src/components/permissions/permission_request.cc +++ b/chromium_src/components/permissions/permission_request.cc @@ -92,6 +92,14 @@ PermissionRequest::PermissionRequest( std::move(permission_decided_callback), std::move(delete_callback)) {} +PermissionRequest::PermissionRequest( + PermissionRequestData request_data, + PermissionDecidedCallback permission_decided_callback, + base::OnceClosure delete_callback) + : PermissionRequest_ChromiumImpl(std::move(request_data), + std::move(permission_decided_callback), + std::move(delete_callback)) {} + PermissionRequest::~PermissionRequest() = default; bool PermissionRequest::SupportsLifetime() const { diff --git a/chromium_src/components/permissions/permission_request.h b/chromium_src/components/permissions/permission_request.h index eaf2188f82f7..478fd6dc4fc7 100644 --- a/chromium_src/components/permissions/permission_request.h +++ b/chromium_src/components/permissions/permission_request.h @@ -25,6 +25,10 @@ class PermissionRequest : public PermissionRequest_ChromiumImpl { PermissionDecidedCallback permission_decided_callback, base::OnceClosure delete_callback); + PermissionRequest(PermissionRequestData request_data, + PermissionDecidedCallback permission_decided_callback, + base::OnceClosure delete_callback); + PermissionRequest(const PermissionRequest&) = delete; PermissionRequest& operator=(const PermissionRequest&) = delete; diff --git a/chromium_src/components/permissions/permission_request_data.cc b/chromium_src/components/permissions/permission_request_data.cc new file mode 100644 index 000000000000..477a89ddf4df --- /dev/null +++ b/chromium_src/components/permissions/permission_request_data.cc @@ -0,0 +1,37 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "components/permissions/permission_request_data.h" +#include "components/permissions/permission_context_base.h" + +namespace permissions { + +absl::optional ContentSettingsTypeToRequestTypeIfExists_BraveImpl( + ContentSettingsType content_settings_type) { + switch (content_settings_type) { + case ContentSettingsType::BRAVE_ETHEREUM: + return RequestType::kBraveEthereum; + case ContentSettingsType::BRAVE_SOLANA: + return RequestType::kBraveSolana; + case ContentSettingsType::BRAVE_GOOGLE_SIGN_IN: + return RequestType::kBraveGoogleSignInPermission; + case ContentSettingsType::BRAVE_LOCALHOST_ACCESS: + return RequestType::kBraveLocalhostAccessPermission; + default: + return ContentSettingsTypeToRequestTypeIfExists(content_settings_type); + } +} + +} // namespace permissions + +#define PermissionContextBase PermissionContextBase_ChromiumImpl + +#define ContentSettingsTypeToRequestTypeIfExists \ + ContentSettingsTypeToRequestTypeIfExists_BraveImpl + +#include "src/components/permissions/permission_request_data.cc" + +#undef ContentSettingsTypeToRequestTypeIfExists +#undef PermissionContextBase diff --git a/chromium_src/components/permissions/permission_request_data.h b/chromium_src/components/permissions/permission_request_data.h new file mode 100644 index 000000000000..3f78403350b7 --- /dev/null +++ b/chromium_src/components/permissions/permission_request_data.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_CHROMIUM_SRC_COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_DATA_H_ +#define BRAVE_CHROMIUM_SRC_COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_DATA_H_ + +#ifndef PermissionContextBase +#define BRAVE_CHROMIUM_SRC_COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_DATA_PERMISSION_CONTEXT_BASE +#define PermissionContextBase PermissionContextBase_ChromiumImpl +#endif + +#include "src/components/permissions/permission_request_data.h" // IWYU pragma: export + +#ifdef BRAVE_CHROMIUM_SRC_COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_DATA_PERMISSION_CONTEXT_BASE +#undef PermissionContextBase +#endif + +#endif // BRAVE_CHROMIUM_SRC_COMPONENTS_PERMISSIONS_PERMISSION_REQUEST_DATA_H_ diff --git a/chromium_src/components/safe_browsing/core/common/features.cc b/chromium_src/components/safe_browsing/core/common/features.cc index bad795c458be..056086db8f42 100644 --- a/chromium_src/components/safe_browsing/core/common/features.cc +++ b/chromium_src/components/safe_browsing/core/common/features.cc @@ -19,6 +19,9 @@ OVERRIDE_FEATURE_DEFAULT_STATES({{ {kExtensionTelemetry, base::FEATURE_DISABLED_BY_DEFAULT}, {kExtensionTelemetryDeclarativeNetRequestSignal, base::FEATURE_DISABLED_BY_DEFAULT}, + {kExtensionTelemetryDisableOffstoreExtensions, + base::FEATURE_DISABLED_BY_DEFAULT}, + {kExtensionTelemetryTabsApiSignal, base::FEATURE_DISABLED_BY_DEFAULT}, }}); } // namespace safe_browsing diff --git a/chromium_src/components/search/ntp_features.cc b/chromium_src/components/search/ntp_features.cc index 0cbe077b8d04..b219c8642115 100644 --- a/chromium_src/components/search/ntp_features.cc +++ b/chromium_src/components/search/ntp_features.cc @@ -11,11 +11,16 @@ namespace ntp_features { OVERRIDE_FEATURE_DEFAULT_STATES({{ + {kCustomizeChromeSidePanelExtensionsCard, + base::FEATURE_DISABLED_BY_DEFAULT}, + {kCustomizeChromeWallpaperSearch, base::FEATURE_DISABLED_BY_DEFAULT}, {kNtpAlphaBackgroundCollections, base::FEATURE_DISABLED_BY_DEFAULT}, {kNtpBackgroundImageErrorDetection, base::FEATURE_DISABLED_BY_DEFAULT}, {kNtpChromeCartModule, base::FEATURE_DISABLED_BY_DEFAULT}, {kNtpHistoryClustersModule, base::FEATURE_DISABLED_BY_DEFAULT}, + {kNtpHistoryClustersModuleDiscounts, base::FEATURE_DISABLED_BY_DEFAULT}, {kNtpHistoryClustersModuleLoad, base::FEATURE_DISABLED_BY_DEFAULT}, + {kNtpModulesMaxColumnCount, base::FEATURE_DISABLED_BY_DEFAULT}, }}); } // namespace ntp_features diff --git a/chromium_src/components/segmentation_platform/public/features.cc b/chromium_src/components/segmentation_platform/public/features.cc index 84613d7426de..3dbe7c49d5f4 100644 --- a/chromium_src/components/segmentation_platform/public/features.cc +++ b/chromium_src/components/segmentation_platform/public/features.cc @@ -12,8 +12,11 @@ namespace segmentation_platform::features { OVERRIDE_FEATURE_DEFAULT_STATES({{ + {kSegmentationPlatformCollectTabRankData, + base::FEATURE_DISABLED_BY_DEFAULT}, {kSegmentationPlatformDeviceTier, base::FEATURE_DISABLED_BY_DEFAULT}, {kSegmentationPlatformFeature, base::FEATURE_DISABLED_BY_DEFAULT}, + {kSegmentationPlatformTimeDelaySampling, base::FEATURE_DISABLED_BY_DEFAULT}, }}); } // namespace segmentation_platform::features diff --git a/chromium_src/components/viz/service/gl/gpu_service_impl.cc b/chromium_src/components/viz/service/gl/gpu_service_impl.cc index 1726799ad2f2..80da3758a8a2 100644 --- a/chromium_src/components/viz/service/gl/gpu_service_impl.cc +++ b/chromium_src/components/viz/service/gl/gpu_service_impl.cc @@ -22,14 +22,14 @@ namespace viz { void GpuServiceImpl::InitializeWithHost( mojo::PendingRemote pending_gpu_host, - gpu::GpuProcessActivityFlags activity_flags, + gpu::GpuProcessShmCount use_shader_cache_shm_count, scoped_refptr default_offscreen_surface, gpu::SyncPointManager* sync_point_manager, gpu::SharedImageManager* shared_image_manager, gpu::Scheduler* scheduler, base::WaitableEvent* shutdown_event) { InitializeWithHost_ChromiumImpl( - std::move(pending_gpu_host), std::move(activity_flags), + std::move(pending_gpu_host), std::move(use_shader_cache_shm_count), std::move(default_offscreen_surface), sync_point_manager, shared_image_manager, scheduler, shutdown_event); #if BUILDFLAG(IS_WIN) diff --git a/chromium_src/components/viz/service/gl/gpu_service_impl.h b/chromium_src/components/viz/service/gl/gpu_service_impl.h index 6bd30803a0b3..6eeccca2b0ea 100644 --- a/chromium_src/components/viz/service/gl/gpu_service_impl.h +++ b/chromium_src/components/viz/service/gl/gpu_service_impl.h @@ -12,7 +12,7 @@ #define InitializeWithHost \ InitializeWithHost_ChromiumImpl( \ mojo::PendingRemote pending_gpu_host, \ - gpu::GpuProcessActivityFlags activity_flags, \ + gpu::GpuProcessShmCount use_shader_cache_shm_count, \ scoped_refptr default_offscreen_surface, \ gpu::SyncPointManager* sync_point_manager, \ gpu::SharedImageManager* shared_image_manager, \ diff --git a/chromium_src/chrome/browser/dips/dips_features.cc b/chromium_src/content/common/features.cc similarity index 65% rename from chromium_src/chrome/browser/dips/dips_features.cc rename to chromium_src/content/common/features.cc index 1b77d2384506..451186a782da 100644 --- a/chromium_src/chrome/browser/dips/dips_features.cc +++ b/chromium_src/content/common/features.cc @@ -3,14 +3,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "src/chrome/browser/dips/dips_features.cc" +#include "src/content/common/features.cc" #include "base/feature_override.h" +#include "build/build_config.h" -namespace dips { +namespace content { OVERRIDE_FEATURE_DEFAULT_STATES({{ - {kFeature, base::FEATURE_DISABLED_BY_DEFAULT}, + {kServiceWorkerAutoPreload, base::FEATURE_DISABLED_BY_DEFAULT}, }}); -} // namespace dips +} // namespace content diff --git a/chromium_src/content/public/common/content_features.cc b/chromium_src/content/public/common/content_features.cc index ce5e1d1b040c..e76a061e04d1 100644 --- a/chromium_src/content/public/common/content_features.cc +++ b/chromium_src/content/public/common/content_features.cc @@ -13,6 +13,7 @@ namespace features { OVERRIDE_FEATURE_DEFAULT_STATES({{ {kAttributionFencedFrameReportingBeacon, base::FEATURE_DISABLED_BY_DEFAULT}, {kDigitalGoodsApi, base::FEATURE_DISABLED_BY_DEFAULT}, + {kDIPS, base::FEATURE_DISABLED_BY_DEFAULT}, {kFedCm, base::FEATURE_DISABLED_BY_DEFAULT}, {kFirstPartySets, base::FEATURE_DISABLED_BY_DEFAULT}, {kIdleDetection, base::FEATURE_DISABLED_BY_DEFAULT}, diff --git a/chromium_src/extensions/browser/api/web_request/extension_web_request_event_router.cc b/chromium_src/extensions/browser/api/web_request/extension_web_request_event_router.cc index 89e0ec25a1c2..1769b0541e57 100644 --- a/chromium_src/extensions/browser/api/web_request/extension_web_request_event_router.cc +++ b/chromium_src/extensions/browser/api/web_request/extension_web_request_event_router.cc @@ -3,10 +3,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at https://mozilla.org/MPL/2.0/. */ -#define BRAVE_EXTENSION_WEB_REQUEST_EVENT_ROUTER_ON_AUTH_REQUIRED \ - ClearSignaled(request->id, kOnBeforeSendHeaders); \ - ClearSignaled(request->id, kOnSendHeaders); \ - ClearSignaled(request->id, kOnHeadersReceived); +#define BRAVE_EXTENSION_WEB_REQUEST_EVENT_ROUTER_ON_AUTH_REQUIRED \ + if (browser_context) { \ + ClearSignaled(browser_context, request->id, kOnBeforeSendHeaders); \ + ClearSignaled(browser_context, request->id, kOnSendHeaders); \ + ClearSignaled(browser_context, request->id, kOnHeadersReceived); \ + } #include "src/extensions/browser/api/web_request/extension_web_request_event_router.cc" diff --git a/chromium_src/ios/chrome/browser/application_context/application_context_impl.mm b/chromium_src/ios/chrome/browser/application_context/model/application_context_impl.mm similarity index 97% rename from chromium_src/ios/chrome/browser/application_context/application_context_impl.mm rename to chromium_src/ios/chrome/browser/application_context/model/application_context_impl.mm index 479f63e3f8c1..8d0794c82a37 100644 --- a/chromium_src/ios/chrome/browser/application_context/application_context_impl.mm +++ b/chromium_src/ios/chrome/browser/application_context/model/application_context_impl.mm @@ -1,9 +1,9 @@ /* Copyright (c) 2020 The Brave Authors. All rights reserved. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include "ios/chrome/browser/application_context/application_context_impl.h" +#include "ios/chrome/browser/application_context/model/application_context_impl.h" #include @@ -63,10 +63,6 @@ #include "services/network/public/cpp/network_connection_tracker.h" #include "services/network/public/cpp/shared_url_loader_factory.h" -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - namespace { // Passed to NetworkConnectionTracker to bind a NetworkChangeManager receiver. @@ -174,8 +170,9 @@ void BindNetworkChangeManagerReceiver( } PrefService* browser_state_prefs = browser_state->GetPrefs(); - if (browser_state_prefs) + if (browser_state_prefs) { browser_state_prefs->CommitPendingWrite(); + } } } @@ -187,8 +184,9 @@ void BindNetworkChangeManagerReceiver( PrefService* ApplicationContextImpl::GetLocalState() { DCHECK(thread_checker_.CalledOnValidThread()); - if (!local_state_) + if (!local_state_) { CreateLocalState(); + } return local_state_.get(); } @@ -223,8 +221,9 @@ void BindNetworkChangeManagerReceiver( ios::ChromeBrowserStateManager* ApplicationContextImpl::GetChromeBrowserStateManager() { DCHECK(thread_checker_.CalledOnValidThread()); - if (!chrome_browser_state_manager_) + if (!chrome_browser_state_manager_) { chrome_browser_state_manager_.reset(new ChromeBrowserStateManagerImpl()); + } return chrome_browser_state_manager_.get(); } diff --git a/chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm index 966f5df69ae7..0c2c9c821db3 100644 --- a/chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm +++ b/chromium_src/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm @@ -6,8 +6,8 @@ #include "ios/chrome/browser/browser_state/browser_state_keyed_service_factories.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" -#include "ios/chrome/browser/bookmarks/bookmark_undo_service_factory.h" -#include "ios/chrome/browser/bookmarks/local_or_syncable_bookmark_model_factory.h" +#include "ios/chrome/browser/bookmarks/model/bookmark_undo_service_factory.h" +#include "ios/chrome/browser/bookmarks/model/local_or_syncable_bookmark_model_factory.h" #include "ios/chrome/browser/consent_auditor/consent_auditor_factory.h" #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" #include "ios/chrome/browser/favicon/favicon_service_factory.h" diff --git a/chromium_src/net/base/features.cc b/chromium_src/net/base/features.cc index b6b470fd1a91..e3c922bd8815 100644 --- a/chromium_src/net/base/features.cc +++ b/chromium_src/net/base/features.cc @@ -26,6 +26,8 @@ OVERRIDE_FEATURE_DEFAULT_STATES({{ // Brave ephemeral storage. For reference: // https://github.com/brave/brave-browser/issues/26165 {kSupportPartitionedBlobUrl, base::FEATURE_DISABLED_BY_DEFAULT}, + {kThirdPartyPartitionedStorageAllowedByDefault, + base::FEATURE_DISABLED_BY_DEFAULT}, }}); BASE_FEATURE(kBraveEphemeralStorage, diff --git a/chromium_src/net/base/schemeful_site.h b/chromium_src/net/base/schemeful_site.h index 07dcda85d3ec..dce0bff1bd17 100644 --- a/chromium_src/net/base/schemeful_site.h +++ b/chromium_src/net/base/schemeful_site.h @@ -6,12 +6,12 @@ #ifndef BRAVE_CHROMIUM_SRC_NET_BASE_SCHEMEFUL_SITE_H_ #define BRAVE_CHROMIUM_SRC_NET_BASE_SCHEMEFUL_SITE_H_ -#define NetworkIsolationKey \ - NetworkIsolationKey; \ +#define IsolationInfo \ + IsolationInfo; \ friend class HSTSPartitionHashHelper #include "src/net/base/schemeful_site.h" // IWYU pragma: export -#undef NetworkIsolationKey +#undef IsolationInfo #endif // BRAVE_CHROMIUM_SRC_NET_BASE_SCHEMEFUL_SITE_H_ diff --git a/chromium_src/python_modules/base/win/embedded_i18n/create_string_rc.py b/chromium_src/python_modules/base/win/embedded_i18n/create_string_rc.py deleted file mode 100644 index 79facdaafd17..000000000000 --- a/chromium_src/python_modules/base/win/embedded_i18n/create_string_rc.py +++ /dev/null @@ -1,86 +0,0 @@ -MODE_SPECIFIC_STRINGS = { - 'IDS_APP_SHORTCUTS_SUBDIR_NAME': { - 'google_chrome': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_BETA', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_DEV', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY', - ], - 'chromium': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - ], - 'brave': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_BETA', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_DEV', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY', - ], - 'brave-development': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - ], - }, - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION': { - 'google_chrome': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_BETA', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_DEV', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY', - ], - 'chromium': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - ], - 'brave': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_BETA', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_DEV', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY', - ], - 'brave-development': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - ], - }, - 'IDS_INBOUND_MDNS_RULE_NAME': { - 'google_chrome': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - 'IDS_INBOUND_MDNS_RULE_NAME_BETA', - 'IDS_INBOUND_MDNS_RULE_NAME_DEV', - 'IDS_INBOUND_MDNS_RULE_NAME_CANARY', - ], - 'chromium': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - ], - 'brave': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - 'IDS_INBOUND_MDNS_RULE_NAME_BETA', - 'IDS_INBOUND_MDNS_RULE_NAME_DEV', - 'IDS_INBOUND_MDNS_RULE_NAME_CANARY', - ], - 'brave-development': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - ], - }, - # In contrast to the strings above, this one (IDS_PRODUCT_NAME) is used - # throughout Chrome in mode-independent contexts. Within the installer (the - # place where this mapping matters), it is only used for mode-specific strings - # such as the name of Chrome's shortcut. - 'IDS_PRODUCT_NAME': { - 'google_chrome': [ - 'IDS_PRODUCT_NAME', - 'IDS_SHORTCUT_NAME_BETA', - 'IDS_SHORTCUT_NAME_DEV', - 'IDS_SXS_SHORTCUT_NAME', - ], - 'chromium': [ - 'IDS_PRODUCT_NAME', - ], - 'brave': [ - 'IDS_PRODUCT_NAME', - 'IDS_SHORTCUT_NAME_BETA', - 'IDS_SHORTCUT_NAME_DEV', - 'IDS_SXS_SHORTCUT_NAME', - ], - 'brave-development': [ - 'IDS_PRODUCT_NAME', - ], - }, -} diff --git a/chromium_src/python_modules/chrome/__init__.py b/chromium_src/python_modules/chrome/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/chromium_src/python_modules/chrome/installer/__init__.py b/chromium_src/python_modules/chrome/installer/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/chromium_src/python_modules/chrome/installer/util/__init__.py b/chromium_src/python_modules/chrome/installer/util/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/chromium_src/python_modules/chrome/installer/util/prebuild/__init__.py b/chromium_src/python_modules/chrome/installer/util/prebuild/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/chromium_src/python_modules/chrome/installer/util/prebuild/create_installer_string_rc.py b/chromium_src/python_modules/chrome/installer/util/prebuild/create_installer_string_rc.py deleted file mode 100644 index 79facdaafd17..000000000000 --- a/chromium_src/python_modules/chrome/installer/util/prebuild/create_installer_string_rc.py +++ /dev/null @@ -1,86 +0,0 @@ -MODE_SPECIFIC_STRINGS = { - 'IDS_APP_SHORTCUTS_SUBDIR_NAME': { - 'google_chrome': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_BETA', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_DEV', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY', - ], - 'chromium': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - ], - 'brave': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_BETA', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_DEV', - 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY', - ], - 'brave-development': [ - 'IDS_APP_SHORTCUTS_SUBDIR_NAME', - ], - }, - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION': { - 'google_chrome': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_BETA', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_DEV', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY', - ], - 'chromium': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - ], - 'brave': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_BETA', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_DEV', - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY', - ], - 'brave-development': [ - 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', - ], - }, - 'IDS_INBOUND_MDNS_RULE_NAME': { - 'google_chrome': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - 'IDS_INBOUND_MDNS_RULE_NAME_BETA', - 'IDS_INBOUND_MDNS_RULE_NAME_DEV', - 'IDS_INBOUND_MDNS_RULE_NAME_CANARY', - ], - 'chromium': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - ], - 'brave': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - 'IDS_INBOUND_MDNS_RULE_NAME_BETA', - 'IDS_INBOUND_MDNS_RULE_NAME_DEV', - 'IDS_INBOUND_MDNS_RULE_NAME_CANARY', - ], - 'brave-development': [ - 'IDS_INBOUND_MDNS_RULE_NAME', - ], - }, - # In contrast to the strings above, this one (IDS_PRODUCT_NAME) is used - # throughout Chrome in mode-independent contexts. Within the installer (the - # place where this mapping matters), it is only used for mode-specific strings - # such as the name of Chrome's shortcut. - 'IDS_PRODUCT_NAME': { - 'google_chrome': [ - 'IDS_PRODUCT_NAME', - 'IDS_SHORTCUT_NAME_BETA', - 'IDS_SHORTCUT_NAME_DEV', - 'IDS_SXS_SHORTCUT_NAME', - ], - 'chromium': [ - 'IDS_PRODUCT_NAME', - ], - 'brave': [ - 'IDS_PRODUCT_NAME', - 'IDS_SHORTCUT_NAME_BETA', - 'IDS_SHORTCUT_NAME_DEV', - 'IDS_SXS_SHORTCUT_NAME', - ], - 'brave-development': [ - 'IDS_PRODUCT_NAME', - ], - }, -} diff --git a/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index 60b7a4767d55..53c5c88cd3ec 100644 --- a/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc @@ -17,12 +17,17 @@ image_data_pixmap.computeByteSize()); \ } +#define BRAVE_BASE_RENDERING_CONTEXT_2D_MEASURE_TEXT \ + if (!brave::AllowFingerprinting(GetTopExecutionContext())) \ + return MakeGarbageCollected(); + #define BRAVE_GET_IMAGE_DATA_PARAMS ScriptState *script_state, #define getImageData getImageData_Unused #include "src/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc" #undef getImageData #undef BRAVE_GET_IMAGE_DATA_PARAMS #undef BRAVE_GET_IMAGE_DATA +#undef BRAVE_BASE_RENDERING_CONTEXT_2D_MEASURE_TEXT namespace { diff --git a/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc index a6b685d0cecb..73aa174a1be3 100644 --- a/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc +++ b/chromium_src/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc @@ -7,14 +7,9 @@ #include "brave/third_party/blink/renderer/core/farbling/brave_session_cache.h" -#define BRAVE_CANVAS_RENDERING_CONTEXT_2D_MEASURE_TEXT \ - if (!brave::AllowFingerprinting(GetExecutionContext())) \ - return MakeGarbageCollected(); - #define getImageDataInternal getImageDataInternal_Unused #include "src/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc" #undef getImageDataInternal -#undef BRAVE_CANVAS_RENDERING_CONTEXT_2D_MEASURE_TEXT namespace blink { diff --git a/chromium_src/v8/src/codegen/compiler.cc b/chromium_src/v8/src/codegen/compiler.cc index e25b9f8f1267..90338d347a67 100644 --- a/chromium_src/v8/src/codegen/compiler.cc +++ b/chromium_src/v8/src/codegen/compiler.cc @@ -9,9 +9,9 @@ IF_BUILDFLAG(ENABLE_BRAVE_PAGE_GRAPH, { \ auto* page_graph_delegate = isolate->page_graph_delegate(); \ if (V8_UNLIKELY(page_graph_delegate)) { \ - Object maybe_script = result->shared().script(); \ + Object maybe_script = result->shared()->script(); \ if (IsScript(maybe_script)) { \ - const int script_id = Script::cast(maybe_script).id(); \ + const int script_id = Script::cast(maybe_script)->id(); \ page_graph_delegate->OnEvalScriptCompiled( \ reinterpret_cast(isolate), script_id, \ v8::Utils::ToLocal(source)); \ diff --git a/chromium_src/v8/src/execution/isolate.cc b/chromium_src/v8/src/execution/isolate.cc index c25d1450c733..3a8871cd08fb 100644 --- a/chromium_src/v8/src/execution/isolate.cc +++ b/chromium_src/v8/src/execution/isolate.cc @@ -25,7 +25,7 @@ GetExecutingScriptsImpl(Isolate* isolate, bool all, bool include_position) { continue; } - const int script_id = Script::cast(maybe_script).id(); + const int script_id = Script::cast(maybe_script)->id(); if (script_id <= 0) { continue; } diff --git a/common/importer/chrome_importer_utils_mac.mm b/common/importer/chrome_importer_utils_mac.mm index d4fb5503d141..1394085b18e6 100644 --- a/common/importer/chrome_importer_utils_mac.mm +++ b/common/importer/chrome_importer_utils_mac.mm @@ -8,55 +8,55 @@ #include "brave/common/importer/chrome_importer_utils.h" +#include "base/apple/foundation_util.h" #include "base/files/file_util.h" -#include "base/mac/foundation_util.h" base::FilePath GetChromeUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Google/Chrome"); } base::FilePath GetChromeBetaUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Google/Chrome Beta"); } base::FilePath GetChromeDevUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Google/Chrome Dev"); } base::FilePath GetCanaryUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Google/Chrome Canary"); } base::FilePath GetVivaldiUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Vivaldi"); } base::FilePath GetChromiumUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Chromium"); } base::FilePath GetEdgeUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Microsoft Edge"); } base::FilePath GetOperaUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/com.operasoftware.Opera"); } base::FilePath GetYandexUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support/Yandex/YandexBrowser"); } base::FilePath GetWhaleUserDataFolder() { - base::FilePath result = base::mac::GetUserLibraryPath(); + base::FilePath result = base::apple::GetUserLibraryPath(); return result.Append("Application Support").Append("Naver").Append("Whale"); } diff --git a/common/resource_bundle_helper.cc b/common/resource_bundle_helper.cc index c7f341e0cebb..0f6070e0b011 100644 --- a/common/resource_bundle_helper.cc +++ b/common/resource_bundle_helper.cc @@ -18,7 +18,7 @@ #endif #if BUILDFLAG(IS_MAC) -#include "base/mac/foundation_util.h" +#include "base/apple/foundation_util.h" #include "base/strings/sys_string_conversions.h" #endif @@ -31,7 +31,7 @@ namespace { #if !BUILDFLAG(IS_ANDROID) base::FilePath GetResourcesPakFilePath() { #if BUILDFLAG(IS_MAC) - return base::mac::PathForFrameworkBundleResource("brave_resources.pak"); + return base::apple::PathForFrameworkBundleResource("brave_resources.pak"); #else base::FilePath pak_path; base::PathService::Get(base::DIR_ASSETS, &pak_path); @@ -50,7 +50,7 @@ base::FilePath GetScaledResourcesPakFilePath( ? "brave_100_percent.pak" : "brave_200_percent.pak"; #if BUILDFLAG(IS_MAC) - return base::mac::PathForFrameworkBundleResource(pak_file); + return base::apple::PathForFrameworkBundleResource(pak_file); #else base::FilePath pak_path; base::PathService::Get(base::DIR_ASSETS, &pak_path); diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index fc61fab0778c..51f1f4fdbeba 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp @@ -113,9 +113,15 @@ - + Save card? + + To pay faster next time, save your card to your device + + + To pay faster next time, save your card, and security code to your device + Save security code? @@ -152,6 +158,23 @@ Save card? + + $1Visa, $24444, expires $301/2025 + + + $1Groceries, $2Visa, $34444, expires $401/2025 + + + + Save card + + + Save card opened at full height. + + + Save card closed. + + Card saved @@ -294,6 +317,32 @@ + + + Something went wrong + + + Something went wrong + + + Virtual card not available + + + Virtual card is not available right now, please try again later + + + Virtual card is not available right now, please contact your bank + + + Not eligible for virtual card + + + This card is not eligible for virtual card number. + + + Close + + Check your CVC and try again @@ -347,7 +396,10 @@ Enter your security code for $1Visa - 5679 - Verifying... + Verifying payment method + + + Payment method verified Verify it's you @@ -456,11 +508,14 @@ Contacting your bank... - + + Using Brave’s security technology to keep your payment info secure + + Cancel - - Your card is confirmed + + Verified Verifying... @@ -617,16 +672,15 @@ - - - Use a virtual card number... + + + Virtual card + + Add virtual card - - Virtual card - {NUM_CARDS, plural, =1 {Use a virtual number for this card} @@ -704,31 +758,22 @@ Virtual card - - Something went wrong - - - Virtual card not available - - - Virtual card is not available right now, please try again later - - - Virtual card is not available right now, please contact your bank - - - Not eligible for virtual card - - - This card is not eligible for virtual card number. - - - Close - Virtual card + + $1Visa **** 1234, virtual card + + + Virtual card enrollment + + + Virtual card enrollment opened at full height + + + Virtual card enrollment closed + Virtual card number not filled in? @@ -801,16 +846,6 @@ Enter correct code - - Remember your UPI ID? - - - Save - - - No thanks - - Cashback linked @@ -864,6 +899,9 @@ $15% off on shoes. Up to $50. $2See Details + + Use this code at checkout + @@ -931,13 +969,13 @@ + + Save security codes + + + Checkout faster when your CVCs are saved + - - Save security codes - - - Checkout faster when your CVCs are saved - Checkout faster when your CVCs are saved. <a href="#">Delete saved security codes</a> @@ -949,4 +987,12 @@ All security codes saved on your device and in Brave sync chain will be deleted + + + Delete saved security codes + + + + CVC + diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp index d555748aca46..efa85164886d 100644 --- a/components/autofill_strings.grdp +++ b/components/autofill_strings.grdp @@ -61,6 +61,9 @@ Delete entry + + Entry $1Jane Doe has been deleted + Delete entry $1Jane Doe @@ -110,7 +113,11 @@ The form was filled in - + + + The edit address option was selected + + The delete address option was selected @@ -119,7 +126,6 @@ The autofilled info was cleared from the form - The fill address fields option was selected @@ -136,7 +142,6 @@ Fill full name - The fill everything option was selected @@ -149,10 +154,30 @@ Manage... + + Edit address + + Delete address + + Building number option selected + + + + Street option selected + + + + Building number + + + + Street + + Fill everything @@ -554,5 +579,8 @@ Cancel + + Expand suggestion + diff --git a/components/brave_rewards/browser/diagnostic_log.cc b/components/brave_rewards/browser/diagnostic_log.cc index 7efaad26e093..b52a85c968e9 100644 --- a/components/brave_rewards/browser/diagnostic_log.cc +++ b/components/brave_rewards/browser/diagnostic_log.cc @@ -21,7 +21,7 @@ const size_t kDividerLength = 80; std::string FormatTime(const base::Time& time) { return base::UTF16ToUTF8( - base::TimeFormatWithPattern(time, "MMM dd, YYYY h::mm::ss.S a")); + base::LocalizedTimeFormatWithPattern(time, "MMM dd, YYYY h::mm::ss.S a")); } std::string GetLogVerboseLevelName(int verbose_level) { diff --git a/components/brave_vpn/browser/brave_vpn_service.cc b/components/brave_vpn/browser/brave_vpn_service.cc index 74abf795fc7a..95b8ff336160 100644 --- a/components/brave_vpn/browser/brave_vpn_service.cc +++ b/components/brave_vpn/browser/brave_vpn_service.cc @@ -550,7 +550,8 @@ void BraveVpnService::OnPrepareCredentialsPresentation( auto env = skus::GetEnvironmentForDomain(domain); // Credential is returned in cookie format. net::CookieInclusionStatus status; - net::ParsedCookie credential_cookie(credential_as_cookie, &status); + net::ParsedCookie credential_cookie(credential_as_cookie, + /*block_truncated=*/true, &status); // TODO(bsclifton): have a better check / logging. // should these failed states be considered NOT_PURCHASED? // or maybe it can be considered FAILED status? diff --git a/components/brave_vpn/browser/connection/ikev2/mac/brave_vpn_ras_connection_api_mac.mm b/components/brave_vpn/browser/connection/ikev2/mac/brave_vpn_ras_connection_api_mac.mm index f9ae25b818d8..d16e514cc3b4 100644 --- a/components/brave_vpn/browser/connection/ikev2/mac/brave_vpn_ras_connection_api_mac.mm +++ b/components/brave_vpn/browser/connection/ikev2/mac/brave_vpn_ras_connection_api_mac.mm @@ -12,10 +12,10 @@ #include #include "base/apple/bundle_locations.h" +#include "base/apple/foundation_util.h" +#include "base/apple/scoped_cftyperef.h" #include "base/files/file_path.h" #include "base/files/file_util.h" -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/notreached.h" #include "base/strings/sys_string_conversions.h" @@ -339,7 +339,7 @@ OSStatus StorePassword(const NSString* password, std::string* error_str) { struct sockaddr_in addr = {0}; addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; - base::ScopedCFTypeRef reachability( + base::apple::ScopedCFTypeRef reachability( SCNetworkReachabilityCreateWithAddress( kCFAllocatorDefault, reinterpret_cast(&addr))); SCNetworkReachabilityFlags flags; diff --git a/components/commerce_strings.grdp b/components/commerce_strings.grdp index 8f3376224862..38a3393cd228 100644 --- a/components/commerce_strings.grdp +++ b/components/commerce_strings.grdp @@ -207,6 +207,20 @@ Something went wrong. + + What is the Shopping list? + + + + A new smart folder that helps you save all your shopping pages in one place, and automatically track prices, get price insights, and more. + + + + + A new smart folder that helps you save all your shopping pages in one place, and automatically track prices, get price insights, and more + + + @@ -279,6 +293,18 @@ Typical prices are based on stores across the web over the past 90 days. + + + + Browse mode, you can change to Forms mode to use the left/right arrow to review price changes on the graph + + + + + You can use the left/right arrow to review price changes on the graph + + + Give feedback @@ -326,6 +352,9 @@ Copy + + $1Use this code at checkout. $2Valid until Aug 15 2023. + Terms and Conditions @@ -398,7 +427,8 @@ Untrack price + - Shopping collection + Shopping list diff --git a/components/components_brave_strings.grd b/components/components_brave_strings.grd index 30a2825f89a3..b81cf80eebb8 100644 --- a/components/components_brave_strings.grd +++ b/components/components_brave_strings.grd @@ -5,105 +5,105 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/components/components_strings.grd b/components/components_strings.grd index fdd890c559f2..2abee4758100 100644 --- a/components/components_strings.grd +++ b/components/components_strings.grd @@ -380,7 +380,7 @@ Save - + Menu diff --git a/components/google_sign_in_permission/google_sign_in_permission_util.cc b/components/google_sign_in_permission/google_sign_in_permission_util.cc index d3ff3f6d1fa5..3828ccea921a 100644 --- a/components/google_sign_in_permission/google_sign_in_permission_util.cc +++ b/components/google_sign_in_permission/google_sign_in_permission_util.cc @@ -21,6 +21,7 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/permission_controller_delegate.h" +#include "content/public/browser/permission_request_description.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" @@ -126,7 +127,9 @@ void CreateGoogleSignInPermissionRequest( *defer = true; } permission_controller->RequestPermissionsFromCurrentDocument( - {blink::PermissionType::BRAVE_GOOGLE_SIGN_IN}, rfh, true, + rfh, + content::PermissionRequestDescription( + blink::PermissionType::BRAVE_GOOGLE_SIGN_IN, /*user_gesture*/ true), std::move(callback)); } diff --git a/components/history_clusters_strings.grdp b/components/history_clusters_strings.grdp index 6c6e1ef2fd7a..a9f21bd9fd29 100644 --- a/components/history_clusters_strings.grdp +++ b/components/history_clusters_strings.grdp @@ -20,13 +20,13 @@ Journeys - + By group List - + By date diff --git a/components/management_strings.grdp b/components/management_strings.grdp index 05664423bca1..648f9fc77178 100644 --- a/components/management_strings.grdp +++ b/components/management_strings.grdp @@ -274,6 +274,9 @@ Performance data and crash reports + + A limited list of URLs of pages you visit where <a target="_blank" href="https://chromestatus.com/features#browsers.chrome.status%3A%22Deprecated%22" >legacy technology events</a> are occuring. + diff --git a/components/media_message_center_strings.grdp b/components/media_message_center_strings.grdp index ac9b67f41abe..92ec63bb0bd0 100644 --- a/components/media_message_center_strings.grdp +++ b/components/media_message_center_strings.grdp @@ -31,8 +31,11 @@ Unmute - - Start casting + + Show device list for casting + + + Hide device list for casting Stop casting diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp index aebe91e497c2..3c5900579752 100644 --- a/components/omnibox_strings.grdp +++ b/components/omnibox_strings.grdp @@ -58,8 +58,8 @@ Offline - - + + Search or type URL diff --git a/components/omnibox_strings_override.grdp b/components/omnibox_strings_override.grdp index 30391569ac4b..f8b10ad7d484 100644 --- a/components/omnibox_strings_override.grdp +++ b/components/omnibox_strings_override.grdp @@ -12,7 +12,7 @@ - + diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp index d84c1ee03638..de19faf5716c 100644 --- a/components/page_info_strings.grdp +++ b/components/page_info_strings.grdp @@ -20,12 +20,21 @@ This site contains malware + + Dangerous site + This site is deceptive + + Dangerous site + This site contains harmful programs + + Dangerous site + @@ -83,12 +92,21 @@ Attackers on this site might attempt to install dangerous programs on your computer that steal or delete your information (for example, photos, passwords, messages, and credit cards). + + Attackers on the site you're trying to visit might install harmful software that steals or deletes things like your password, photos, messages, or credit card number. + Attackers on this site may trick you into doing something dangerous like installing software or revealing your personal information (for example, passwords, phone numbers, or credit cards). + + Attackers on the site you're trying to visit might trick you into installing software or revealing things like your password, phone, or credit card number. + Attackers on this site might try to trick you into installing programs that harm your browsing experience (for example, by changing your homepage or showing extra ads on sites you visit). + + Attackers on the site you're trying to visit might trick you into installing harmful software that affects the way you browse — for example, by changing your homepage or showing you extra ads on sites you visit. + @@ -363,11 +381,17 @@ Select permission for $1Location + + Allow $1example.com to use info they've saved about you + Can ask to track your camera position + + Can ask to automatically open picture-in-picture windows + Can ask to automatically download multiple files @@ -629,13 +653,13 @@ Expires On - Fingerprints + SHA-256 Fingerprints - - SHA-256 Fingerprint + + Certificate - - SHA-1 Fingerprint + + Public Key diff --git a/components/password_manager_strings.grdp b/components/password_manager_strings.grdp index 386e7e1cb434..3b4f17d9b63d 100644 --- a/components/password_manager_strings.grdp +++ b/components/password_manager_strings.grdp @@ -68,6 +68,9 @@ Use passwords saved in your Brave sync chain + + Use passwords and passkeys saved in your Brave sync chain + Sign in to use passwords saved in your Brave sync chain @@ -123,6 +126,21 @@ Use device sign-in + + Passkey from your Brave Profile + + + Passkey from iCloud Keychain + + + Passkey from "$1Dashlane" + + + Passkey from Windows Hello + + + Passkey from "$1Pixel 7" + Use a Passkey on a Different Device @@ -133,6 +151,26 @@ Use a passkey on a different device + + + Use a Different Passkey + + + + + Use a different passkey + + + + + Use a Passkey + + + + + Use a passkey + + Brave is trying to fill your password on $1google.com. diff --git a/components/pdf_strings.grdp b/components/pdf_strings.grdp index ded9ab1d804f..dda05157f503 100644 --- a/components/pdf_strings.grdp +++ b/components/pdf_strings.grdp @@ -354,23 +354,35 @@ - - Press search plus m and convert image to text in the context menu - + + + + This PDF is inaccessible. Press search plus m to open context menu and turn on "extract text from PDF" + + + + + This PDF is inaccessible. Open context menu and turn on "extract text from PDF" + + + - Image is being analyzed + This PDF is inaccessible. Extracting text, powered by Brave AI - Image converted to text + This PDF is inaccessible. Text extracted, powered by Brave AI - No text converted from images + This PDF is inaccessible. No text extracted - Start of converted text + Start of extracted text - End of converted text + End of extracted text + + + Extracting text in next few pages diff --git a/components/permissions/brave_permission_manager.cc b/components/permissions/brave_permission_manager.cc index e59ec702f918..1c424621cc12 100644 --- a/components/permissions/brave_permission_manager.cc +++ b/components/permissions/brave_permission_manager.cc @@ -10,6 +10,7 @@ #include "base/auto_reset.h" #include "components/permissions/permission_context_base.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/permission_request_description.h" #include "url/origin.h" namespace permissions { @@ -35,7 +36,9 @@ void BravePermissionManager::RequestPermissionsForOrigin( base::AutoReset auto_reset_requesting_origin(&forced_requesting_origin_, requesting_origin); return RequestPermissionsFromCurrentDocument( - permissions, render_frame_host, user_gesture, std::move(callback)); + render_frame_host, + content::PermissionRequestDescription(permissions, user_gesture), + std::move(callback)); } blink::mojom::PermissionStatus diff --git a/components/permissions/contexts/brave_wallet_permission_context.cc b/components/permissions/contexts/brave_wallet_permission_context.cc index 634be949c911..67728c989ebc 100644 --- a/components/permissions/contexts/brave_wallet_permission_context.cc +++ b/components/permissions/contexts/brave_wallet_permission_context.cc @@ -14,6 +14,7 @@ #include "components/content_settings/core/common/content_settings_types.h" #include "components/permissions/permission_manager.h" #include "components/permissions/permission_request.h" +#include "components/permissions/permission_request_data.h" #include "components/permissions/permission_request_id.h" #include "components/permissions/permission_request_manager.h" #include "components/permissions/permissions_client.h" @@ -60,12 +61,11 @@ bool BraveWalletPermissionContext::IsRestrictedToSecureOrigins() const { } void BraveWalletPermissionContext::RequestPermission( - const PermissionRequestID& id, - const GURL& requesting_frame, - bool user_gesture, + PermissionRequestData request_data, BrowserPermissionCallback callback) { - const std::string id_str = id.ToString(); - url::Origin requesting_origin = url::Origin::Create(requesting_frame); + const std::string id_str = request_data.id.ToString(); + url::Origin requesting_origin = + url::Origin::Create(request_data.requesting_origin); url::Origin origin; permissions::RequestType type = ContentSettingsTypeToRequestType(content_settings_type()); @@ -78,15 +78,16 @@ void BraveWalletPermissionContext::RequestPermission( if (!brave_wallet::ParseRequestingOrigin( type, requesting_origin, &origin, is_new_id ? &address_queue : nullptr)) { - content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(id.global_render_frame_host_id()); + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( + request_data.id.global_render_frame_host_id()); content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(rfh); GURL embedding_origin = url::Origin::Create(web_contents->GetLastCommittedURL()).GetURL(); - NotifyPermissionSet(id, requesting_origin.GetURL(), embedding_origin, - std::move(callback), /*persist=*/false, - CONTENT_SETTING_BLOCK, /*is_one_time=*/false, + NotifyPermissionSet(request_data.id, requesting_origin.GetURL(), + embedding_origin, std::move(callback), + /*persist=*/false, CONTENT_SETTING_BLOCK, + /*is_one_time=*/false, /*is_final_decision=*/true); return; } @@ -107,8 +108,10 @@ void BraveWalletPermissionContext::RequestPermission( if (addr_queue.empty()) { request_address_queues_.erase(addr_queue_it); } - PermissionContextBase::RequestPermission(id, sub_request_origin.GetURL(), - user_gesture, std::move(callback)); + PermissionContextBase::RequestPermission( + PermissionRequestData(this, request_data.id, request_data.user_gesture, + sub_request_origin.GetURL()), + std::move(callback)); } // static diff --git a/components/permissions/contexts/brave_wallet_permission_context.h b/components/permissions/contexts/brave_wallet_permission_context.h index 90d725375826..e776c06993ca 100644 --- a/components/permissions/contexts/brave_wallet_permission_context.h +++ b/components/permissions/contexts/brave_wallet_permission_context.h @@ -18,8 +18,6 @@ #include "third_party/blink/public/common/permissions/permission_utils.h" #include "url/origin.h" -class GURL; - namespace content { class BrowserContext; class WebContents; @@ -46,9 +44,7 @@ class BraveWalletPermissionContext : public PermissionContextBase { * will then consume one address from the saved list and call * PermissionContextBase::RequestPermission with it. */ - void RequestPermission(const PermissionRequestID& id, - const GURL& requesting_frame, - bool user_gesture, + void RequestPermission(PermissionRequestData request_data, BrowserPermissionCallback callback) override; static void RequestPermissions( diff --git a/components/permissions_strings.grdp b/components/permissions_strings.grdp index 00deac4a806f..42760d864072 100644 --- a/components/permissions_strings.grdp +++ b/components/permissions_strings.grdp @@ -46,8 +46,11 @@ $1mail.google.com wants to send you notifications + + $1www.google.com wants to use your MIDI devices + - $1www.google.com wants to get full control of your MIDI devices + $1www.google.com wants to control and reprogram your MIDI devices (SysEx) $1news.site wants to use cookies and site data on $2content_domain.site @@ -92,9 +95,12 @@ Show notifications - + Use your MIDI devices + + Control and reprogram your MIDI devices (SysEx) + Use your microphone @@ -128,7 +134,7 @@ Do you want to allow $1news.site to use co This will otherwise be blocked by your privacy settings. This will allow the content you interacted with to work correctly, but may allow $1news.site to track your activity. - $1google.com will know that you visited $2top-level-site.com. $3Learn more about embedded content. + $1google.com will know that you visited $2top-level-site.com. Learn more about embedded content @@ -237,8 +243,11 @@ This will otherwise be blocked by your privacy settings. This will allow the con Get notifications? + + Use MIDI devices? + - Connect MIDI device? + Control and reprogram MIDI devices? Use microphone? diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp index 4e189cbb41d8..6e9c12093412 100644 --- a/components/policy_strings.grdp +++ b/components/policy_strings.grdp @@ -726,6 +726,12 @@ Additional details: Copy as JSON + + View logs + + + More actions + diff --git a/components/privacy_sandbox_strings.grdp b/components/privacy_sandbox_strings.grdp index c5420fe6dfff..d148c5f3b886 100644 --- a/components/privacy_sandbox_strings.grdp +++ b/components/privacy_sandbox_strings.grdp @@ -1,40 +1,6 @@ - - None - - - {NUM_DAYS, plural, - =0 {When this control is on and the status is active, Brave determines which large group of profiles, or "cohort," your recent browsing activity is most similar to. Advertisers can select ads for the group and your browsing activity is kept private on your device. Your group is updated every day.} - =1 {When this control is on and the status is active, Brave determines which large group of profiles, or "cohort," your recent browsing activity is most similar to. Advertisers can select ads for the group and your browsing activity is kept private on your device. Your group is updated every day.} - other {When this control is on and the status is active, Brave determines which large group of profiles, or "cohort," your recent browsing activity is most similar to. Advertisers can select ads for the group and your browsing activity is kept private on your device. Your group is updated every {NUM_DAYS} days.}} - - - {NUM_DAYS, plural, - =0 {In less than a day} - =1 {In a day} - other {In {NUM_DAYS} days}} - - - Not applicable - - - {NUM_DAYS, plural, - =0 {You can reset your group at any time. It takes about a day to join a new group.} - =1 {You can reset your group at any time. It takes about a day to join a new group.} - other {You can reset your group at any time. It takes {NUM_DAYS} days to join a new group.}} - - - Trial is active - - - Eligible for trial but not active - - - Off - - Turn on an ad privacy feature diff --git a/components/privacy_sandbox_strings_override.grdp b/components/privacy_sandbox_strings_override.grdp index 2e92ee8aa18a..abd3bfb6446e 100644 --- a/components/privacy_sandbox_strings_override.grdp +++ b/components/privacy_sandbox_strings_override.grdp @@ -1,12 +1,6 @@ - - {NUM_DAYS, plural, - =0 {When this control is on and the status is active, Brave determines which large group of profiles, or "cohort," your recent browsing activity is most similar to. Advertisers can select ads for the group and your browsing activity is kept private on your device. Your group is updated every day.} - =1 {When this control is on and the status is active, Brave determines which large group of profiles, or "cohort," your recent browsing activity is most similar to. Advertisers can select ads for the group and your browsing activity is kept private on your device. Your group is updated every day.} - other {When this control is on and the status is active, Brave determines which large group of profiles, or "cohort," your recent browsing activity is most similar to. Advertisers can select ads for the group and your browsing activity is kept private on your device. Your group is updated every {NUM_DAYS} days.}} - - + Profiles & society diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp index 77db25040c33..c15841c0d9e1 100644 --- a/components/security_interstitials_strings.grdp +++ b/components/security_interstitials_strings.grdp @@ -241,6 +241,9 @@ Back to safety + + Dangerous site + @@ -278,12 +281,27 @@ If you understand the risks to your security, you may <a href="#" id="proceed-link">visit this unsafe site</a> before the dangerous programs have been removed. + + Attackers on the site you're trying to visit might install harmful software that steals or deletes things like your password, photos, messages, or credit card number. Brave strongly recommends going back to safety. <a href="#" id="learn-more-link">Learn more</a> + + + Brave has built-in safety features to protect you while you browse — like Google Safe Browsing, which <a href="#" id="diagnostic-link">recently found malware</a> on the site you're trying to visit. + + + Brave has built-in safety features to protect you while you browse, like Google Safe Browsing. Safe Browsing <a href="#" id="diagnostic-link">recently found malware on $1example.com</a>, which is embedded in the site you're trying to visit. + + + Even sites that are normally safe are sometimes compromised by attackers. Only visit <a href="#" id="proceed-link">this unsafe site</a> if you're sure you understand the risks. + Help improve security on the web for everyone by sending <a href="#" id="whitepaper-link">URLs of some pages you visit, limited system information, and some page content</a> to Brave. <a id="privacy-link" href="#">Privacy policy</a> To get Brave’s highest level of security, <a href="#" id="enhanced-protection-link">turn on enhanced protection</a> + + <a href="#" id="enhanced-protection-link">Turn on enhanced protection</a> to get Brave's highest level of security + @@ -321,6 +339,22 @@ + + Attackers on the site you're trying to visit might trick you into installing harmful software that affects the way you browse — for example, by changing your homepage or showing you extra ads on sites you visit. Brave strongly recommends going back to safety to avoid harm. <a href="#" id="learn-more-link">Learn more</a> + + + + Brave has built-in safety features to protect you while you browse — like Google Safe Browsing, which recently <a href="#" id="diagnostic-link">found harmful software</a> on the site you're trying to visit. + + + + Brave has built-in safety features to protect you while you browse, like Google Safe Browsing. Safe Browsing recently <a href="#" id="diagnostic-link">found harmful software on $1example.com</a>, which is embedded in the site if you're trying to visit. + + + + Even sites that are normally safe are sometimes compromised by attackers. Only visit <a href="#" id="proceed-link">this unsafe site</a> if you're sure you understand the risks. + + Deceptive site ahead @@ -334,6 +368,18 @@ You can <a href="#" id="report-error-link">report a detection problem</a> or, if you understand the risks to your security, <a href="#" id="proceed-link">visit this unsafe site</a>. + + Attackers on the site you're trying to visit might trick you into installing software or revealing things like your password, phone, or credit card number. Brave strongly recommends going back to safety. <a href="#" id="learn-more-link">Learn more</a> + + + Brave has built-in safety features to protect you while you browse — like Google Safe Browsing, which <a href="#" id="diagnostic-link">recently found phishing</a> on the site you're trying to visit. Phishing sites pretend to be other sites to trick you.<br/><br/>Even sites that are normally safe are sometimes compromised by attackers. <a href="#" id="report-error-link">Let us know</a> if you think there's been a mistake and that this site doesn't pose a danger. + + + Brave has built-in safety features to protect you while you browse, like Google Safe Browsing. Safe Browsing recently <a href="#" id="diagnostic-link">found phishing on $1example.com</a>, which is embedded in the site you're trying to visit.<br/><br/>Even sites that are normally safe are sometimes compromised by attackers. <a href="#" id="report-error-link">Let us know</a> if you think there's been a mistake and that this site doesn't pose a danger. + + + Only visit <a href="#" id="proceed-link">this unsafe site</a> if you're sure you understand the risks. + diff --git a/components/site_settings_strings.grdp b/components/site_settings_strings.grdp index 2b3cb6ccad8e..63bdfa4d52da 100644 --- a/components/site_settings_strings.grdp +++ b/components/site_settings_strings.grdp @@ -23,6 +23,12 @@ automatic downloads + + Auto picture-in-picture + + + auto picture-in-picture + Background sync diff --git a/components/text_recognition/browser/text_recognition.mm b/components/text_recognition/browser/text_recognition.mm index c6fd5bff151a..b0a66b76ef9d 100644 --- a/components/text_recognition/browser/text_recognition.mm +++ b/components/text_recognition/browser/text_recognition.mm @@ -8,10 +8,10 @@ #import #import +#include "base/apple/foundation_util.h" +#include "base/apple/scoped_cftyperef.h" #include "base/logging.h" -#include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/strings/sys_string_conversions.h" #include "base/threading/scoped_blocking_call.h" #include "skia/ext/skia_utils_base.h" @@ -66,7 +66,8 @@ } NSError* error = nil; - base::ScopedCFTypeRef cg_image(SkCreateCGImageRef(image)); + base::apple::ScopedCFTypeRef cg_image( + SkCreateCGImageRef(image)); VNImageRequestHandler* requestHandler = [[VNImageRequestHandler alloc] initWithCGImage:cg_image.get() options:@{}]; diff --git a/components/version_ui_strings.grdp b/components/version_ui_strings.grdp index fc1adf06ab3d..32fad769fc5d 100644 --- a/components/version_ui_strings.grdp +++ b/components/version_ui_strings.grdp @@ -54,7 +54,7 @@ Command Line - + Build Date @@ -68,6 +68,9 @@ Copy version string + + Copied version string to clipboard + Executable Path diff --git a/components/webxr_strings.grdp b/components/webxr_strings.grdp index 50fd4451aba9..383d229eeaa3 100644 --- a/components/webxr_strings.grdp +++ b/components/webxr_strings.grdp @@ -14,4 +14,12 @@ View augmented reality content + + + Product safety + + + Use another device + + diff --git a/installer/util/prebuild/create_installer_string_rc.py b/installer/util/prebuild/create_installer_string_rc.py new file mode 100644 index 000000000000..35d911bbe794 --- /dev/null +++ b/installer/util/prebuild/create_installer_string_rc.py @@ -0,0 +1,33 @@ +# Copyright (c) 2023 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import import_inline + +import_inline.inline_file_from_src( + "chrome/installer/util/prebuild/create_installer_string_rc.py", globals(), + locals()) + +MODE_SPECIFIC_STRINGS = { + 'IDS_APP_SHORTCUTS_SUBDIR_NAME': { + 'brave': [ + 'IDS_APP_SHORTCUTS_SUBDIR_NAME', + ], + }, + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION': { + 'brave': [ + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', + ], + }, + 'IDS_INBOUND_MDNS_RULE_NAME': { + 'brave': [ + 'IDS_INBOUND_MDNS_RULE_NAME', + ], + }, + 'IDS_PRODUCT_NAME': { + 'brave': [ + 'IDS_PRODUCT_NAME', + ], + }, +} diff --git a/installer/util/prebuild/create_installer_string_rc_official.py b/installer/util/prebuild/create_installer_string_rc_official.py new file mode 100644 index 000000000000..55c1092439d1 --- /dev/null +++ b/installer/util/prebuild/create_installer_string_rc_official.py @@ -0,0 +1,45 @@ +# Copyright (c) 2023 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import import_inline + +import_inline.inline_file_from_src( + "chrome/installer/util/prebuild/create_installer_string_rc.py", globals(), + locals()) + +MODE_SPECIFIC_STRINGS = { + 'IDS_APP_SHORTCUTS_SUBDIR_NAME': { + 'brave': [ + 'IDS_APP_SHORTCUTS_SUBDIR_NAME', + 'IDS_APP_SHORTCUTS_SUBDIR_NAME_BETA', + 'IDS_APP_SHORTCUTS_SUBDIR_NAME_DEV', + 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY', + ], + }, + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION': { + 'brave': [ + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_BETA', + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_DEV', + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY', + ], + }, + 'IDS_INBOUND_MDNS_RULE_NAME': { + 'brave': [ + 'IDS_INBOUND_MDNS_RULE_NAME', + 'IDS_INBOUND_MDNS_RULE_NAME_BETA', + 'IDS_INBOUND_MDNS_RULE_NAME_DEV', + 'IDS_INBOUND_MDNS_RULE_NAME_CANARY', + ], + }, + 'IDS_PRODUCT_NAME': { + 'brave': [ + 'IDS_PRODUCT_NAME', + 'IDS_SHORTCUT_NAME_BETA', + 'IDS_SHORTCUT_NAME_DEV', + 'IDS_SXS_SHORTCUT_NAME', + ], + }, +} diff --git a/installer/util/sources.gni b/installer/util/sources.gni new file mode 100644 index 000000000000..0510766aa4c9 --- /dev/null +++ b/installer/util/sources.gni @@ -0,0 +1,12 @@ +# Copyright (c) 2023 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +if (is_official_build) { + brave_installer_util_generate_strings_extractor_datafile = + "//brave/installer/util/prebuild/create_installer_string_rc_official.py" +} else { + brave_installer_util_generate_strings_extractor_datafile = + "//brave/installer/util/prebuild/create_installer_string_rc.py" +} diff --git a/ios/app/BUILD.gn b/ios/app/BUILD.gn index b841860b82e6..54d9a1317251 100644 --- a/ios/app/BUILD.gn +++ b/ios/app/BUILD.gn @@ -68,7 +68,7 @@ source_set("app") { "//ios/chrome/app:tests_fake_hook", "//ios/chrome/app/startup:startup", "//ios/chrome/app/startup:startup_basic", - "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/bookmarks/model", "//ios/chrome/browser/browser_state:browser_state", "//ios/chrome/browser/flags:system_flags", "//ios/chrome/browser/history", diff --git a/ios/app/brave_core_main.mm b/ios/app/brave_core_main.mm index c07597a53aa5..6d4a8d9c9eb2 100644 --- a/ios/app/brave_core_main.mm +++ b/ios/app/brave_core_main.mm @@ -9,11 +9,11 @@ #import #include "base/apple/bundle_locations.h" +#include "base/apple/foundation_util.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/i18n/icu_util.h" #include "base/logging.h" -#include "base/mac/foundation_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/path_service.h" @@ -51,9 +51,8 @@ #include "components/prefs/pref_service.h" #include "components/send_tab_to_self/send_tab_to_self_sync_service.h" #include "ios/chrome/app/startup/provider_registration.h" -#include "ios/chrome/browser/bookmarks/bookmark_undo_service_factory.h" -#include "ios/chrome/browser/bookmarks/local_or_syncable_bookmark_model_factory.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state_removal_controller.h" +#include "ios/chrome/browser/bookmarks/model/bookmark_undo_service_factory.h" +#include "ios/chrome/browser/bookmarks/model/local_or_syncable_bookmark_model_factory.h" #include "ios/chrome/browser/history/history_service_factory.h" #include "ios/chrome/browser/history/web_history_service_factory.h" #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" @@ -152,7 +151,7 @@ - (instancetype)initWithUserAgent:(NSString*)userAgent } NSBundle* baseBundle = base::apple::OuterBundle(); - base::mac::SetBaseBundleID( + base::apple::SetBaseBundleID( base::SysNSStringToUTF8([baseBundle bundleIdentifier]).c_str()); // Register all providers before calling any Chromium code. @@ -196,10 +195,6 @@ - (instancetype)initWithUserAgent:(NSString*)userAgent // Setup WebMain _webMain = std::make_unique(std::move(params)); - // Remove the extra browser states as Chrome iOS is single profile in M48+. - ChromeBrowserStateRemovalController::GetInstance() - ->RemoveBrowserStatesIfNecessary(); - // Initialize and set the main browser state. ios::ChromeBrowserStateManager* browserStateManager = GetApplicationContext()->GetChromeBrowserStateManager(); diff --git a/ios/browser/BUILD.gn b/ios/browser/BUILD.gn index de2b74a35c12..eaccdb4a27f7 100644 --- a/ios/browser/BUILD.gn +++ b/ios/browser/BUILD.gn @@ -46,7 +46,7 @@ source_set("browser") { "//components/metrics_services_manager", "//components/variations", "//components/variations/service", - "//ios/chrome/browser/application_context", + "//ios/chrome/browser/application_context/model", "//ios/chrome/browser/browser_state:browser_state", "//ios/chrome/browser/flags", "//ios/chrome/browser/flags:client_side", diff --git a/ios/browser/api/bookmarks/BUILD.gn b/ios/browser/api/bookmarks/BUILD.gn index c121211a1de7..7dd90c787ecd 100644 --- a/ios/browser/api/bookmarks/BUILD.gn +++ b/ios/browser/api/bookmarks/BUILD.gn @@ -22,7 +22,7 @@ source_set("bookmarks") { "//components/prefs", "//components/undo", "//components/user_prefs", - "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/bookmarks/model", "//ios/chrome/browser/shared/model/application_context", "//ios/chrome/browser/shared/model/browser_state", "//ios/chrome/browser/ui/bookmarks", diff --git a/ios/browser/api/bookmarks/exporter/BUILD.gn b/ios/browser/api/bookmarks/exporter/BUILD.gn index d1a4cac4039e..fa2e69ecaf33 100644 --- a/ios/browser/api/bookmarks/exporter/BUILD.gn +++ b/ios/browser/api/bookmarks/exporter/BUILD.gn @@ -25,7 +25,7 @@ source_set("exporter") { "//components/favicon_base", "//components/keyed_service/core", "//components/strings:components_strings_grit", - "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/bookmarks/model", "//ios/chrome/browser/favicon:favicon", "//ios/chrome/browser/shared/model/application_context", "//ios/chrome/browser/shared/model/browser_state", diff --git a/ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc b/ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc index cf3aa31ef12c..a0f910676910 100644 --- a/ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc +++ b/ios/browser/api/bookmarks/exporter/bookmark_html_writer.cc @@ -34,7 +34,7 @@ #include "components/favicon_base/favicon_types.h" #include "components/keyed_service/core/service_access_type.h" #include "components/strings/grit/components_strings.h" -#include "ios/chrome/browser/bookmarks/local_or_syncable_bookmark_model_factory.h" +#include "ios/chrome/browser/bookmarks/model/local_or_syncable_bookmark_model_factory.h" #include "ios/chrome/browser/favicon/favicon_service_factory.h" #include "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/shared/model/browser_state/chrome_browser_state_manager.h" diff --git a/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm b/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm index 1d36cd3e5207..7a1cd0c2a674 100644 --- a/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm +++ b/ios/browser/api/bookmarks/exporter/brave_bookmarks_exporter.mm @@ -9,12 +9,12 @@ #include #include +#include "base/apple/foundation_util.h" #include "base/base_paths.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" -#include "base/mac/foundation_util.h" #include "base/path_service.h" #include "base/strings/sys_string_conversions.h" #include "base/task/sequenced_task_runner.h" @@ -103,7 +103,7 @@ - (void)exportToFile:(NSString*)filePath DCHECK(GetApplicationContext()); base::FilePath destination_file_path = - base::mac::NSStringToFilePath(filePath); + base::apple::NSStringToFilePath(filePath); listener(BraveBookmarksExporterStateStarted); @@ -148,7 +148,7 @@ - (void)exportToFile:(NSString*)filePath listener(BraveBookmarksExporterStateStarted); base::FilePath destination_file_path = - base::mac::NSStringToFilePath(filePath); + base::apple::NSStringToFilePath(filePath); // Create artificial nodes auto bookmark_bar_node = [exporter getBookmarksBarNode]; diff --git a/ios/browser/api/bookmarks/importer/BUILD.gn b/ios/browser/api/bookmarks/importer/BUILD.gn index 7dd3169b7059..699e13a31bf7 100644 --- a/ios/browser/api/bookmarks/importer/BUILD.gn +++ b/ios/browser/api/bookmarks/importer/BUILD.gn @@ -29,7 +29,7 @@ source_set("importer") { "//components/search_engines:search_engines", "//components/strings:components_strings_grit", "//components/user_prefs:user_prefs", - "//ios/chrome/browser/bookmarks", + "//ios/chrome/browser/bookmarks/model", "//ios/chrome/browser/shared/model/application_context", "//ios/chrome/browser/shared/model/browser_state", "//ios/web/public/thread", diff --git a/ios/browser/api/bookmarks/importer/bookmarks_importer.mm b/ios/browser/api/bookmarks/importer/bookmarks_importer.mm index 693212de67db..929767c001ab 100644 --- a/ios/browser/api/bookmarks/importer/bookmarks_importer.mm +++ b/ios/browser/api/bookmarks/importer/bookmarks_importer.mm @@ -23,7 +23,7 @@ #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #include "components/user_prefs/user_prefs.h" -#include "ios/chrome/browser/bookmarks/local_or_syncable_bookmark_model_factory.h" +#include "ios/chrome/browser/bookmarks/model/local_or_syncable_bookmark_model_factory.h" #include "ios/chrome/browser/shared/model/application_context/application_context.h" #include "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/shared/model/browser_state/chrome_browser_state_manager.h" diff --git a/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm b/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm index 8a5f263a6d0e..97dde2fb25f5 100644 --- a/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm +++ b/ios/browser/api/bookmarks/importer/brave_bookmarks_importer.mm @@ -7,12 +7,12 @@ #include +#include "base/apple/foundation_util.h" #include "base/base_paths.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" -#include "base/mac/foundation_util.h" #include "base/path_service.h" #include "base/stl_util.h" #include "base/strings/sys_string_conversions.h" @@ -97,7 +97,7 @@ - (void)importFromFile:(NSString*)filePath withListener: (void (^)(BraveBookmarksImporterState, NSArray* _Nullable))listener { - base::FilePath source_file_path = base::mac::NSStringToFilePath(filePath); + base::FilePath source_file_path = base::apple::NSStringToFilePath(filePath); // In Chromium, this is IDS_BOOKMARK_GROUP (804) std::u16string top_level_folder_name = base::SysNSStringToUTF16(folderName); diff --git a/ios/browser/api/certificate/brave_certificate.mm b/ios/browser/api/certificate/brave_certificate.mm index 59ede285d480..8957d32f5458 100644 --- a/ios/browser/api/certificate/brave_certificate.mm +++ b/ios/browser/api/certificate/brave_certificate.mm @@ -34,23 +34,23 @@ // MARK: - Implementation @interface BraveCertificateModel () { - base::ScopedCFTypeRef cert_data_; + base::apple::ScopedCFTypeRef cert_data_; std::shared_ptr extended_cert_; - base::ScopedCFTypeRef public_key_; + base::apple::ScopedCFTypeRef public_key_; } @end @implementation BraveCertificateModel - (nullable instancetype)initWithCertificate:(SecCertificateRef)certificate { if ((self = [super init])) { - cert_data_ = - base::ScopedCFTypeRef(SecCertificateCopyData(certificate)); + cert_data_ = base::apple::ScopedCFTypeRef( + SecCertificateCopyData(certificate)); if (!cert_data_) { return nullptr; } - public_key_ = - base::ScopedCFTypeRef(SecCertificateCopyKey(certificate)); + public_key_ = base::apple::ScopedCFTypeRef( + SecCertificateCopyKey(certificate)); bssl::UniquePtr cert_buffer( net::x509_util::CreateCryptoBuffer(base::make_span( diff --git a/ios/browser/api/net/certificate_utility.mm b/ios/browser/api/net/certificate_utility.mm index cd69d20ac345..9bd6cb1295aa 100644 --- a/ios/browser/api/net/certificate_utility.mm +++ b/ios/browser/api/net/certificate_utility.mm @@ -9,11 +9,11 @@ #include #include +#import "base/apple/foundation_util.h" #include "base/base64.h" #include "base/containers/span.h" #include "base/functional/bind.h" #include "base/logging.h" -#import "base/mac/foundation_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #import "base/notreached.h" @@ -67,8 +67,9 @@ @implementation BraveCertificateUtility } + (NSString*)pemEncodeCertificate:(SecCertificateRef)certificate { - base::ScopedCFTypeRef cert_data = - base::ScopedCFTypeRef(SecCertificateCopyData(certificate)); + base::apple::ScopedCFTypeRef cert_data = + base::apple::ScopedCFTypeRef( + SecCertificateCopyData(certificate)); if (!cert_data) { return nil; } @@ -91,8 +92,9 @@ + (NSString*)pemEncodeCertificate:(SecCertificateRef)certificate { } + (NSData*)hashCertificateSPKI:(SecCertificateRef)certificate { - base::ScopedCFTypeRef cert_data = - base::ScopedCFTypeRef(SecCertificateCopyData(certificate)); + base::apple::ScopedCFTypeRef cert_data = + base::apple::ScopedCFTypeRef( + SecCertificateCopyData(certificate)); if (!cert_data) { return nil; } @@ -141,22 +143,22 @@ + (int)verifyTrust:(SecTrustRef)trust return nullptr; } - std::vector> intermediates; + std::vector> intermediates; - base::ScopedCFTypeRef certificateChain( + base::apple::ScopedCFTypeRef certificateChain( SecTrustCopyCertificateChain(trust)); for (CFIndex i = 1; i < cert_count; i++) { SecCertificateRef secCertificate = - base::mac::CFCastStrict( + base::apple::CFCastStrict( CFArrayGetValueAtIndex(certificateChain, i)); intermediates.emplace_back(secCertificate, base::scoped_policy::RETAIN); } SecCertificateRef secCertificate = - base::mac::CFCastStrict( + base::apple::CFCastStrict( CFArrayGetValueAtIndex(certificateChain, 0)); return net::x509_util::CreateX509CertificateFromSecCertificate( - base::ScopedCFTypeRef(secCertificate, - base::scoped_policy::RETAIN), + base::apple::ScopedCFTypeRef( + secCertificate, base::scoped_policy::RETAIN), intermediates); }; diff --git a/ios/browser/api/sync/brave_sync_worker.cc b/ios/browser/api/sync/brave_sync_worker.cc index 9d91a76f6371..81f5f425f88d 100644 --- a/ios/browser/api/sync/brave_sync_worker.cc +++ b/ios/browser/api/sync/brave_sync_worker.cc @@ -432,14 +432,13 @@ void BraveSyncWorker::OnResetDone() { bool BraveSyncWorker::CanSyncFeatureStart() { DCHECK_CURRENTLY_ON(web::WebThread::UI); - auto* setup_service = - SyncSetupServiceFactory::GetForBrowserState(browser_state_); + syncer::SyncService* sync_service = GetSyncService(); - if (!setup_service) { + if (!sync_service) { return false; } - return setup_service->IsSyncFeatureEnabled(); + return sync_service->IsSyncFeatureEnabled(); } bool BraveSyncWorker::IsSyncFeatureActive() { diff --git a/ios/browser/application_context/BUILD.gn b/ios/browser/application_context/BUILD.gn index 3c3e1e74272f..d9c4c79ed555 100644 --- a/ios/browser/application_context/BUILD.gn +++ b/ios/browser/application_context/BUILD.gn @@ -15,7 +15,7 @@ source_set("application_context") { "//base", "//brave/components/brave_component_updater/browser", "//brave/components/url_sanitizer/browser", - "//ios/chrome/browser/application_context", + "//ios/chrome/browser/application_context/model", "//ios/chrome/browser/shared/model/application_context", ] } diff --git a/ios/browser/application_context/brave_application_context_impl.h b/ios/browser/application_context/brave_application_context_impl.h index d414736f6aec..71e2af9bea13 100644 --- a/ios/browser/application_context/brave_application_context_impl.h +++ b/ios/browser/application_context/brave_application_context_impl.h @@ -11,7 +11,7 @@ #include "brave/components/brave_component_updater/browser/brave_component.h" #include "brave/components/url_sanitizer/browser/url_sanitizer_component_installer.h" -#include "ios/chrome/browser/application_context/application_context_impl.h" +#include "ios/chrome/browser/application_context/model/application_context_impl.h" namespace base { class CommandLine; diff --git a/ios/browser/brave_web_main_parts.mm b/ios/browser/brave_web_main_parts.mm index 340781cebe1f..b4256e6c5bb3 100644 --- a/ios/browser/brave_web_main_parts.mm +++ b/ios/browser/brave_web_main_parts.mm @@ -20,7 +20,7 @@ #include "components/variations/synthetic_trials_active_group_id_provider.h" #include "components/variations/variations_ids_provider.h" #include "components/variations/variations_switches.h" -#include "ios/chrome/browser/application_context/application_context_impl.h" +#include "ios/chrome/browser/application_context/model/application_context_impl.h" #include "ios/chrome/browser/browser_state/browser_state_keyed_service_factories.h" #include "ios/chrome/browser/flags/about_flags.h" #include "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" diff --git a/ios/browser/providers/BUILD.gn b/ios/browser/providers/BUILD.gn index 491cbaac9c85..a96fe61170f0 100644 --- a/ios/browser/providers/BUILD.gn +++ b/ios/browser/providers/BUILD.gn @@ -29,6 +29,7 @@ group("brave_providers") { "//ios/chrome/browser/providers/overrides:chromium_overrides", "//ios/chrome/browser/providers/partial_translate:chromium_partial_translate", "//ios/chrome/browser/providers/password_auto_fill:chromium_password_auto_fill", + "//ios/chrome/browser/providers/photos:chromium_photos", "//ios/chrome/browser/providers/primes:chromium_primes", "//ios/chrome/browser/providers/push_notification:chromium_push_notification", "//ios/chrome/browser/providers/risk_data:chromium_risk_data", diff --git a/net/http/partitioned_host_state_map_unittest.cc b/net/http/partitioned_host_state_map_unittest.cc index cb4fe7e860aa..a424421654d0 100644 --- a/net/http/partitioned_host_state_map_unittest.cc +++ b/net/http/partitioned_host_state_map_unittest.cc @@ -10,6 +10,7 @@ #include #include "base/containers/span.h" +#include "base/strings/string_piece.h" #include "crypto/sha2.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/package.json b/package.json index 69472bd7f926..3cba6ef84db4 100644 --- a/package.json +++ b/package.json @@ -267,7 +267,7 @@ "projects": { "chrome": { "dir": "src", - "tag": "117.0.5938.92", + "tag": "118.0.5993.21", "repository": { "url": "https://github.com/brave/chromium" } diff --git a/patches/base-BUILD.gn.patch b/patches/base-BUILD.gn.patch index cb37748d2d5d..406619d3822c 100644 --- a/patches/base-BUILD.gn.patch +++ b/patches/base-BUILD.gn.patch @@ -1,12 +1,12 @@ diff --git a/base/BUILD.gn b/base/BUILD.gn -index 6e6f24e479cce61b5f189faed40601e8f3e82ef9..96b0c277a9a89d28a7862104f9c2b0bb803dfc0e 100644 +index 82cb596dcbb369cf67addf856dfe8c0789449e78..e6be16420eb0ecac0158072065cac54be619f4d8 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn -@@ -4396,6 +4396,7 @@ if (is_android) { +@@ -4422,6 +4422,7 @@ if (is_android) { "android/java/src/org/chromium/base/task/ThreadPoolTaskExecutor.java", "android/java/src/org/chromium/base/task/UiThreadTaskExecutor.java", ] + sources += brave_java_base_sources - if (!is_cronet_build) { - sources += [ "android/java/src/org/chromium/base/IntentUtils.java" ] + if (use_clang_profiling) { + sources += [ diff --git a/patches/base-threading-thread_restrictions.h.patch b/patches/base-threading-thread_restrictions.h.patch index 9e83d5e52b77..c8f28a5cec3b 100644 --- a/patches/base-threading-thread_restrictions.h.patch +++ b/patches/base-threading-thread_restrictions.h.patch @@ -1,8 +1,8 @@ diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h -index b88010ec63528497fc2ae0b7b3fc04c0fdd2e539..d67d398f23a567c1793edd3b3766832a85100e07 100644 +index 61ef504585b1347799be57205f1f7f87d01f5aec..96904b027f1f561236051d4da61f4fe662d8c67c 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h -@@ -731,6 +731,7 @@ class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitives { +@@ -710,6 +710,7 @@ class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedAllowBaseSyncPrimitives { ScopedAllowBaseSyncPrimitives& operator=( const ScopedAllowBaseSyncPrimitives&) = delete; diff --git a/patches/base-trace_event-builtin_categories.h.patch b/patches/base-trace_event-builtin_categories.h.patch index dc1add7d22d4..defd8c55784d 100644 --- a/patches/base-trace_event-builtin_categories.h.patch +++ b/patches/base-trace_event-builtin_categories.h.patch @@ -1,5 +1,5 @@ diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h -index 5d1c694fba219f1f0dbb398d16da7b779dc0afcd..15d9af06c5703999c04d953b9435172e8217e81e 100644 +index 292e5ce4922b37a642233a70672d777f5ec6143a..d2a9e629a8b2d660560f85afc63abd89874c4ade 100644 --- a/base/trace_event/builtin_categories.h +++ b/base/trace_event/builtin_categories.h @@ -191,6 +191,7 @@ diff --git a/patches/build-android-gyp-proguard.py.patch b/patches/build-android-gyp-proguard.py.patch index 579ccfa7fe94..66e4c71b98f2 100644 --- a/patches/build-android-gyp-proguard.py.patch +++ b/patches/build-android-gyp-proguard.py.patch @@ -1,5 +1,5 @@ diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py -index c00343ab8d73565a53749be7c113b82621606cd6..424d0889379ccc9abe76b352785429c8aa7f401c 100755 +index 89a1b2dd3dfc6a58c1c350587d76395028b21b32..601ee249ae18d2e38b5427aa895f1a89517ed1ba 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py @@ -329,6 +329,7 @@ def _OptimizeWithR8(options, config_paths, libraries, dynamic_config_data): diff --git a/patches/build-config-android-config.gni.patch b/patches/build-config-android-config.gni.patch index 57672fcdfaf8..12ad9d947190 100644 --- a/patches/build-config-android-config.gni.patch +++ b/patches/build-config-android-config.gni.patch @@ -1,5 +1,5 @@ diff --git a/build/config/android/config.gni b/build/config/android/config.gni -index 0a4ea11f8436ae4bac9c202b81bf24ba959636e9..320c6d0633b113b784d6a51a63a37db01458fd98 100644 +index d8d9a6b8de8788c4dad03b6bdb0ca33c8348fd02..686d5361d3b63ea7034c1d16b60c0e96a26e0269 100644 --- a/build/config/android/config.gni +++ b/build/config/android/config.gni @@ -22,6 +22,7 @@ declare_args() { diff --git a/patches/build-config-android-rules.gni.patch b/patches/build-config-android-rules.gni.patch index 168254a3e6da..0e1d91b8ed80 100644 --- a/patches/build-config-android-rules.gni.patch +++ b/patches/build-config-android-rules.gni.patch @@ -1,8 +1,8 @@ diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni -index 758dbe2a66cbcbc3164e771059d02c4285db2eb5..c512b39b4e472fa9f12bd5836963418225694d14 100644 +index 9fd501ff10137a903e87213b9ed29ec975420e1e..c68234ab0609deb949614dbf1c3cb0d08e69d00d 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni -@@ -428,6 +428,7 @@ if (enable_java_templates && is_android) { +@@ -285,6 +285,7 @@ if (enable_java_templates && is_android) { # ] # } template("java_cpp_enum") { @@ -10,7 +10,7 @@ index 758dbe2a66cbcbc3164e771059d02c4285db2eb5..c512b39b4e472fa9f12bd58369634182 action_with_pydeps(target_name) { forward_variables_from(invoker, TESTONLY_AND_VISIBILITY + [ "sources" ]) -@@ -603,6 +604,7 @@ if (enable_java_templates && is_android) { +@@ -460,6 +461,7 @@ if (enable_java_templates && is_android) { # output = "$target_gen_dir/AndroidManifest.xml" # } template("jinja_template") { diff --git a/patches/build-config-chrome_build.gni.patch b/patches/build-config-chrome_build.gni.patch index ef10d452f52a..3d9a918a2371 100644 --- a/patches/build-config-chrome_build.gni.patch +++ b/patches/build-config-chrome_build.gni.patch @@ -1,5 +1,5 @@ diff --git a/build/config/chrome_build.gni b/build/config/chrome_build.gni -index b5156d5c677a4e990cca5b5f2024a0fb8f09120c..d5f71b8ef29ad462aeb6c5f0b920e2b26514d06b 100644 +index e44aeaa5715d9abe65d6bba5cd4fee43e164566e..499ce2d53e96e746da2c00cce1d3b62014729a66 100644 --- a/build/config/chrome_build.gni +++ b/build/config/chrome_build.gni @@ -1,6 +1,7 @@ diff --git a/patches/build-rust-cargo_crate.gni.patch b/patches/build-rust-cargo_crate.gni.patch index b50f6f67dbc3..d8f45fe7350f 100644 --- a/patches/build-rust-cargo_crate.gni.patch +++ b/patches/build-rust-cargo_crate.gni.patch @@ -1,13 +1,21 @@ diff --git a/build/rust/cargo_crate.gni b/build/rust/cargo_crate.gni -index 7471b015c2d66516211a2b36ec77fbcf60854722..c54e8a7baa5c60fb47c8d3e8b5a86a1bdf7b4902 100644 +index 427fcf69da0b5b15f972b58e3988c7d103bae80d..12cfea27becb565b28ba667f1efb326c2754de68 100644 --- a/build/rust/cargo_crate.gni +++ b/build/rust/cargo_crate.gni -@@ -190,7 +190,7 @@ template("cargo_crate") { +@@ -153,6 +153,7 @@ template("cargo_crate") { + manifest_dir = rebase_path(build_gn_dir + "/crate", "") + } + _rustenv += [ "CARGO_MANIFEST_DIR=${manifest_dir}" ] ++ _rustenv -= [ "CARGO_MANIFEST_DIR=${manifest_dir}" ] + + # cargo_crate() should set library_configs, executable_configs, + # proc_macro_configs. Not configs. +@@ -214,7 +215,7 @@ template("cargo_crate") { "rustenv", "dev_deps", ]) - forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) + forward_variables_from(invoker, [ "testonly" ]) - - rustc_metadata = _rustc_metadata - + if (defined(crate_type) && crate_type == "cdylib") { + # See comments above about cdylib. + crate_type = "rlib" diff --git a/patches/build-rust-std-remap_alloc.cc.patch b/patches/build-rust-std-remap_alloc.cc.patch index 9f0549a6a42c..a33ee3d193b2 100644 --- a/patches/build-rust-std-remap_alloc.cc.patch +++ b/patches/build-rust-std-remap_alloc.cc.patch @@ -1,8 +1,8 @@ diff --git a/build/rust/std/remap_alloc.cc b/build/rust/std/remap_alloc.cc -index 6d010b61873104f99dc5b39669af3b3d79dd6f6d..767883d3d3bc76ab80f37c7a18b7efcd315e4215 100644 +index bfd39b724b88a8de963840c617430eb0d3875f03..41c3b7317d5310c70156e5aafca5a30cefa08e0f 100644 --- a/build/rust/std/remap_alloc.cc +++ b/build/rust/std/remap_alloc.cc -@@ -129,7 +129,15 @@ REMAP_ALLOC_ATTRIBUTES void* __rust_alloc(size_t size, size_t align) { +@@ -130,7 +130,15 @@ REMAP_ALLOC_ATTRIBUTES void* __rust_alloc(size_t size, size_t align) { } REMAP_ALLOC_ATTRIBUTES void __rust_dealloc(void* p, size_t size, size_t align) { diff --git a/patches/build-util-android_chrome_version.py.patch b/patches/build-util-android_chrome_version.py.patch index a9998331f6af..9634807b9b20 100644 --- a/patches/build-util-android_chrome_version.py.patch +++ b/patches/build-util-android_chrome_version.py.patch @@ -1,8 +1,8 @@ diff --git a/build/util/android_chrome_version.py b/build/util/android_chrome_version.py -index 41b22a0de9fbd135b50d9cfadd4fa78c52cc1ec7..56e9da9a35c7471acb73d1ca9a96335f7ffeb63d 100755 +index 16cf8d04033041608f09aca89610b644c30ab916..8bc041563e4bfd105a34a69aa83e3808f634b4c5 100755 --- a/build/util/android_chrome_version.py +++ b/build/util/android_chrome_version.py -@@ -199,6 +199,7 @@ def _GetAbisToDigitMask(build_number, patch_number): +@@ -200,6 +200,7 @@ def _GetAbisToDigitMask(build_number, patch_number): mapped to version code suffix. """ # Scheme change was made directly to M113 and M114 branches. @@ -10,7 +10,7 @@ index 41b22a0de9fbd135b50d9cfadd4fa78c52cc1ec7..56e9da9a35c7471acb73d1ca9a96335f use_new_scheme = (build_number >= 5750 or (build_number == 5672 and patch_number >= 176) or (build_number == 5735 and patch_number >= 53)) -@@ -332,7 +333,7 @@ def GenerateVersionCodes(version_values, arch, is_next_build): +@@ -333,7 +334,7 @@ def GenerateVersionCodes(version_values, arch, is_next_build): build_number = int(version_values['BUILD']) patch_number = int(version_values['PATCH']) diff --git a/patches/chrome-BUILD.gn.patch b/patches/chrome-BUILD.gn.patch index c45055471ec2..200b60694346 100644 --- a/patches/chrome-BUILD.gn.patch +++ b/patches/chrome-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn -index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb3697f9e521 100644 +index bc54ace77cade8c2e2439af6d0c18984cfdaf5c6..a63dd1fc5e762fb29f571d0123d51028987b3699 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn -@@ -201,6 +201,7 @@ if (!is_android && !is_mac) { +@@ -198,6 +198,7 @@ if (!is_android && !is_mac) { "common/crash_keys.cc", "common/crash_keys.h", ] @@ -10,7 +10,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 deps += [ ":chrome_dll", -@@ -519,11 +520,12 @@ if (is_win) { +@@ -518,11 +519,12 @@ if (is_win) { args += [ "--keystone=0" ] } } @@ -24,7 +24,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 extra_substitutions = [ "CHROMIUM_BUNDLE_ID=$chrome_mac_bundle_id", "CHROMIUM_SHORT_NAME=$chrome_product_short_name", -@@ -543,6 +545,7 @@ if (is_win) { +@@ -542,6 +544,7 @@ if (is_win) { "//chrome/common:buildflags", "//chrome/common:version_header", ] @@ -32,16 +32,16 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 if (enable_updater) { deps += [ ":chromium_updater_privileged_helper" ] -@@ -619,7 +622,7 @@ if (is_win) { - args = - [ - "-b", -- "${branding_path_product}_strings", -+ _strings_file, - "-v", - chrome_version_full, - "-g", -@@ -693,6 +696,7 @@ if (is_win) { +@@ -601,7 +604,7 @@ if (is_win) { + if (is_chrome_branded) { + _strings_file = "google_chrome_strings" + } else { +- _strings_file = "chromium_strings" ++ _strings_file = "${branding_path_product}_strings" + } + + inputs += [ "$root_gen_dir/chrome/${_strings_file}_${locale}.pak" ] +@@ -686,6 +689,7 @@ if (is_win) { # this dependency directly copies the file into the framework's # resources directory. public_deps += [ ":chrome_framework_widevine_signature" ] @@ -49,7 +49,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 } } -@@ -736,9 +740,11 @@ if (is_win) { +@@ -731,9 +735,11 @@ if (is_win) { "--scm=0", ] } @@ -61,7 +61,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 if (is_chrome_branded && include_branded_entitlements) { # These entitlements are bound to the official Google Chrome signing # certificate and will not necessarily work in any other build. -@@ -763,6 +769,7 @@ if (is_win) { +@@ -758,6 +764,7 @@ if (is_win) { info_plist_target = invoker.info_plist_target } else { info_plist_target = ":chrome_helper_plist" @@ -69,7 +69,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 } extra_substitutions = [ -@@ -941,6 +948,7 @@ if (is_win) { +@@ -936,6 +943,7 @@ if (is_win) { sources += [ "//third_party/updater/chrome_mac_universal_prod/${updater_product_full_name}.app" ] } else { sources += [ "$root_out_dir/${updater_product_full_name}.app" ] @@ -77,7 +77,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 public_deps += [ "//chrome/updater/mac:browser_install_script", -@@ -1276,6 +1284,7 @@ if (is_win) { +@@ -1272,6 +1280,7 @@ if (is_win) { "-current_version", chrome_dylib_version, ] @@ -85,7 +85,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 if (!is_component_build) { # Specify a sensible install_name for static builds. The library is -@@ -1456,6 +1465,7 @@ if (is_win) { +@@ -1452,6 +1461,7 @@ if (is_win) { group("dependencies") { public_deps = [ @@ -93,7 +93,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 "//build:branding_buildflags", "//build:chromeos_buildflags", "//chrome/browser", -@@ -1522,7 +1532,7 @@ group("dependencies") { +@@ -1518,7 +1528,7 @@ group("dependencies") { if (is_win) { process_version_rc_template("chrome_exe_version") { @@ -102,7 +102,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 output = "$target_gen_dir/chrome_exe_version.rc" } -@@ -1576,6 +1586,7 @@ group("resources") { +@@ -1572,6 +1582,7 @@ group("resources") { "//chrome/browser:resources", "//chrome/common:resources", "//chrome/renderer:resources", @@ -110,7 +110,7 @@ index 61f07f736047732cc631c713fafa507df48ebb90..d5dd6542ad941a15456274997204eb36 ] } -@@ -1629,6 +1640,7 @@ if (!is_android) { +@@ -1625,6 +1636,7 @@ if (!is_android) { if (enable_resource_allowlist_generation) { repack_allowlist = _chrome_resource_allowlist deps = [ ":resource_allowlist" ] diff --git a/patches/chrome-VERSION.patch b/patches/chrome-VERSION.patch index d960e0cc829b..a13e4cd79632 100644 --- a/patches/chrome-VERSION.patch +++ b/patches/chrome-VERSION.patch @@ -1,12 +1,12 @@ diff --git a/chrome/VERSION b/chrome/VERSION -index ce84aab37d587593f77c8467a1a3c938805d5e0b..738953cb0efa08230a31500c96c7b23b13b40f2b 100644 +index 17b8c90d10dc82c5e1c2caec58fd1af7b217c0d7..3ac21869b4a626d7ef83ecd2aee5dea0ed482a3c 100644 --- a/chrome/VERSION +++ b/chrome/VERSION @@ -1,4 +1,4 @@ - MAJOR=117 + MAJOR=118 -MINOR=0 --BUILD=5938 --PATCH=92 +-BUILD=5993 +-PATCH=21 +MINOR=1 +BUILD=60 +PATCH=61 diff --git a/patches/chrome-android-BUILD.gn.patch b/patches/chrome-android-BUILD.gn.patch index 822a5d5d363b..6568ac9e8f9a 100644 --- a/patches/chrome-android-BUILD.gn.patch +++ b/patches/chrome-android-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn -index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748ee8a48e24 100644 +index e89e2f7d23cdf9552e15026fd805580c99d673e6..b4099f14e9467237e3ceed0569579cd759e0c9db 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn @@ -169,6 +169,7 @@ if (current_toolchain == default_toolchain) { @@ -10,7 +10,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e } android_resources("chrome_app_java_resources") { -@@ -236,6 +237,7 @@ if (current_toolchain == default_toolchain) { +@@ -237,6 +238,7 @@ if (current_toolchain == default_toolchain) { "//third_party/androidx:androidx_gridlayout_gridlayout_java", "//third_party/androidx:androidx_preference_preference_java", ] @@ -18,7 +18,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e } android_library("app_hooks_java") { -@@ -640,6 +642,7 @@ if (current_toolchain == default_toolchain) { +@@ -654,6 +656,7 @@ if (current_toolchain == default_toolchain) { ] deps += feed_deps @@ -26,7 +26,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e srcjar_deps = [ ":chrome_android_java_enums_srcjar", -@@ -659,6 +662,7 @@ if (current_toolchain == default_toolchain) { +@@ -672,6 +675,7 @@ if (current_toolchain == default_toolchain) { "//components/supervised_user/core/browser:supervised_user_url_filter_enum_javagen", "//net:effective_connection_type_java", ] @@ -34,7 +34,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e # From java_sources.gni. sources = chrome_java_sources + [ app_hooks_impl ] -@@ -792,6 +796,7 @@ if (current_toolchain == default_toolchain) { +@@ -806,6 +810,7 @@ if (current_toolchain == default_toolchain) { "//components/messages/android/internal:java", "//components/segmentation_platform/internal:internal_java", ] @@ -42,7 +42,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e } action_with_pydeps("chrome_android_java_google_api_keys_srcjar") { -@@ -2099,6 +2104,7 @@ if (current_toolchain == default_toolchain) { +@@ -2121,6 +2126,7 @@ if (current_toolchain == default_toolchain) { "java/res_chromium_base/mipmap-xxxhdpi/layered_app_icon_background.png", "java/res_chromium_base/values/channel_constants.xml", ] @@ -50,7 +50,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e # Dep needed to ensure override works properly. deps = [ ":chrome_base_module_resources" ] -@@ -2318,6 +2324,7 @@ if (current_toolchain == default_toolchain) { +@@ -2340,6 +2346,7 @@ if (current_toolchain == default_toolchain) { ":${_variant}_locale_pak_assets", ":${_variant}_paks", ] @@ -58,7 +58,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e if (_is_monochrome) { deps += [ "//android_webview:locale_pak_assets" ] if (webview_includes_weblayer && !_is_bundle_module) { -@@ -2590,6 +2597,7 @@ if (current_toolchain == default_toolchain) { +@@ -2612,6 +2619,7 @@ if (current_toolchain == default_toolchain) { "//components/payments/content/android:service_java", "//third_party/androidx:androidx_browser_browser_java", ] @@ -66,7 +66,7 @@ index d7ceb4f02120ec22640efc0ab92706c06a110c01..6677ae1444cefaea6beb62fac84e748e # More deps for DFMs. if (dfmify_dev_ui) { -@@ -3523,6 +3531,7 @@ generate_jni("chrome_jni_headers") { +@@ -3550,6 +3558,7 @@ generate_jni("chrome_jni_headers") { "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java", "java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java", ] diff --git a/patches/chrome-android-chrome_java_sources.gni.patch b/patches/chrome-android-chrome_java_sources.gni.patch index c090a165dbdb..b4e5a273dbe4 100644 --- a/patches/chrome-android-chrome_java_sources.gni.patch +++ b/patches/chrome-android-chrome_java_sources.gni.patch @@ -1,5 +1,5 @@ diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni -index a67d20641971d0c9618c28c5d9049b4df9b9bb63..ff7acdb33cf8f73825838b67f726f2abae9a73fb 100644 +index f4d274b24e1120bf7e8a4bab31ec7628f24610df..556e36df338efe0927bfe07b27eb47324e6b59a9 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni @@ -1211,3 +1211,4 @@ chrome_java_sources = [ diff --git a/patches/chrome-android-chrome_public_apk_tmpl.gni.patch b/patches/chrome-android-chrome_public_apk_tmpl.gni.patch index a337a0907700..1bb76d69c34f 100644 --- a/patches/chrome-android-chrome_public_apk_tmpl.gni.patch +++ b/patches/chrome-android-chrome_public_apk_tmpl.gni.patch @@ -1,5 +1,5 @@ diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni -index 5122a76e6c951f4eec0fdd83437e8c3df1d0856e..e76e2134b26c2ce655f77ce33ef96ccf4da7e6ff 100644 +index ba3b2534130b96d44170a36567187688e86acc9a..2c514ce2d64b139476dc310960df94c57638a994 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni @@ -314,6 +314,7 @@ template("chrome_common_apk_or_module_tmpl") { @@ -18,7 +18,7 @@ index 5122a76e6c951f4eec0fdd83437e8c3df1d0856e..e76e2134b26c2ce655f77ce33ef96ccf if (_is_monochrome) { proguard_configs += [ "//android_webview/nonembedded/java/proguard.flags" ] -@@ -746,6 +748,7 @@ template("chrome_common_apk_or_module_tmpl") { +@@ -749,6 +751,7 @@ template("chrome_common_apk_or_module_tmpl") { "version_code", "version_name", ]) @@ -26,7 +26,7 @@ index 5122a76e6c951f4eec0fdd83437e8c3df1d0856e..e76e2134b26c2ce655f77ce33ef96ccf } } -@@ -774,6 +777,7 @@ template("monochrome_public_common_apk_or_module_tmpl") { +@@ -777,6 +780,7 @@ template("monochrome_public_common_apk_or_module_tmpl") { if (!defined(is_monochrome)) { is_trichrome = true } diff --git a/patches/chrome-android-java-AndroidManifest.xml.patch b/patches/chrome-android-java-AndroidManifest.xml.patch index 1c6938ff8f17..478a135ea09f 100644 --- a/patches/chrome-android-java-AndroidManifest.xml.patch +++ b/patches/chrome-android-java-AndroidManifest.xml.patch @@ -1,5 +1,5 @@ diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml -index 298dfaabe9ce9c383c2e3b00590ce23e6904d2a7..0d77669f198557016b6c1e7c42f5c03cbbbe64b8 100644 +index e4c9f334a89237c467f5e7485d97c361bd0a4b9a..f4cef65c0ce1990112602350da22d3c61a87c1dc 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml @@ -28,6 +28,7 @@ by a child template that "extends" this file. @@ -66,7 +66,7 @@ index 298dfaabe9ce9c383c2e3b00590ce23e6904d2a7..0d77669f198557016b6c1e7c42f5c03c -@@ -1218,6 +1232,7 @@ by a child template that "extends" this file. +@@ -1222,6 +1236,7 @@ by a child template that "extends" this file. {% endif %} diff --git a/patches/chrome-android-java-src-org-chromium-chrome-browser-tabbed_mode-TabbedRootUiCoordinator.java.patch b/patches/chrome-android-java-src-org-chromium-chrome-browser-tabbed_mode-TabbedRootUiCoordinator.java.patch index 4ae12ef7aeb6..358dd5bbd351 100644 --- a/patches/chrome-android-java-src-org-chromium-chrome-browser-tabbed_mode-TabbedRootUiCoordinator.java.patch +++ b/patches/chrome-android-java-src-org-chromium-chrome-browser-tabbed_mode-TabbedRootUiCoordinator.java.patch @@ -1,8 +1,8 @@ diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java -index 7f494b05c003ff94d51b1fbb1f8e799b717c0611..db9bef6484953024b31ea14c164665857dab1564 100644 +index 6558fa1debd9c27766518e818a0c50c5082f9c12..0016e08102837df80b624788791f124b496a07ac 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java -@@ -702,7 +702,7 @@ public class TabbedRootUiCoordinator extends RootUiCoordinator { +@@ -700,7 +700,7 @@ public class TabbedRootUiCoordinator extends RootUiCoordinator { NotificationPermissionController.attach( mWindowAndroid, mNotificationPermissionController); diff --git a/patches/chrome-app-BUILD.gn.patch b/patches/chrome-app-BUILD.gn.patch index 5b92b99a2f5a..51883694226c 100644 --- a/patches/chrome-app-BUILD.gn.patch +++ b/patches/chrome-app-BUILD.gn.patch @@ -1,22 +1,12 @@ diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn -index 8179dd92317a4cbafb65bdefd5c27f9848bca0d7..411ad5c908ceb4aac150a5ac1844d288057c71f2 100644 +index 7b5a8e56879b7aab545da6ca847d809020e11e96..49dd37f2d9fa3acf45a1d890b9a565c9d4ebfd5d 100644 --- a/chrome/app/BUILD.gn +++ b/chrome/app/BUILD.gn -@@ -124,6 +124,8 @@ grit("generated_resources") { +@@ -117,6 +117,7 @@ grit("generated_resources") { if (is_android) { outputs += android_generated_java_resources } -+ + deps = [ "//brave/app:brave_generated_resources_grit" ] } if (is_android) { -@@ -159,7 +161,7 @@ grit("google_chrome_strings") { - } - - grit("chromium_strings") { -- source = "chromium_strings.grd" -+ source = "${branding_path_component}_strings.grd" - defines = chrome_grit_defines - output_dir = "$root_gen_dir/chrome" - outputs = diff --git a/patches/chrome-browser-BUILD.gn.patch b/patches/chrome-browser-BUILD.gn.patch index 933d23a3810f..d67bf943fd16 100644 --- a/patches/chrome-browser-BUILD.gn.patch +++ b/patches/chrome-browser-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn -index ff490f2ffb3f5af65d8af96ff708f9292ffb5e33..949a451d9369766c0c56fb4985f2ee2f632b52af 100644 +index 9ab6c039d18f8759b8d7db9742d3570a7734f893..0d3c0da47a4daf59becae0a06449cbe48e8327ce 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn -@@ -2587,6 +2587,7 @@ static_library("browser") { +@@ -2623,6 +2623,7 @@ static_library("browser") { "metrics/family_link_user_metrics_provider.h", ] } diff --git a/patches/chrome-browser-about_flags.cc.patch b/patches/chrome-browser-about_flags.cc.patch index 6f4dcb46612f..9249a8ffae0e 100644 --- a/patches/chrome-browser-about_flags.cc.patch +++ b/patches/chrome-browser-about_flags.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc -index 6dd44c495824833aecddbb76582836ffb7c5a593..1106dbc7e077f424635d0f0229f89cda7a53cc30 100644 +index 7574fc11e1f61df6cd9a173743e0602fc09a1454..64aff9d03a21decb088d60f1269f584dae6abff0 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc -@@ -3819,6 +3819,7 @@ const FeatureEntry::FeatureVariation kPasswordGenerationExperimentVariations[] = +@@ -3807,6 +3807,7 @@ const FeatureEntry::FeatureVariation kPasswordGenerationExperimentVariations[] = // // When adding a new choice, add it to the end of the list. const FeatureEntry kFeatureEntries[] = { diff --git a/patches/chrome-browser-app_controller_mac.mm.patch b/patches/chrome-browser-app_controller_mac.mm.patch index c2d99f25ea9a..8eda5a5c83ae 100644 --- a/patches/chrome-browser-app_controller_mac.mm.patch +++ b/patches/chrome-browser-app_controller_mac.mm.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm -index 32b5fd746c0e300638010e03282cfc97ff9260ac..d45f86bddb9a9222f5e24869459be8b6e9d1a4db 100644 +index db6cf130160312e15dbc0444b3cf27b91fb3eb86..5f81bc3fa743570df55bded7586ec2d308d16641 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm -@@ -644,7 +644,7 @@ class AppControllerNativeThemeObserver : public ui::NativeThemeObserver { +@@ -645,7 +645,7 @@ class AppControllerNativeThemeObserver : public ui::NativeThemeObserver { + (AppController*)sharedController { static AppController* sharedController = [] { @@ -11,7 +11,7 @@ index 32b5fd746c0e300638010e03282cfc97ff9260ac..d45f86bddb9a9222f5e24869459be8b6 NSApp.delegate = sharedController; return sharedController; }(); -@@ -1183,7 +1183,7 @@ class AppControllerNativeThemeObserver : public ui::NativeThemeObserver { +@@ -1181,7 +1181,7 @@ class AppControllerNativeThemeObserver : public ui::NativeThemeObserver { } auto it = _profileBookmarkMenuBridgeMap.find(profilePath); diff --git a/patches/chrome-browser-browser_process_impl.h.patch b/patches/chrome-browser-browser_process_impl.h.patch index cae297b126c4..cb2909cb82a0 100644 --- a/patches/chrome-browser-browser_process_impl.h.patch +++ b/patches/chrome-browser-browser_process_impl.h.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h -index 43d7af86dbd67cccb6a9dffdc3e1c2a2e69130f5..68fe495b2e11dba1a95a12ec779ca32985237fff 100644 +index 7cc361a82a6230da4ace07469e7454728d767a74..b0b0f5960146b0414b55f711e45d9143e5d21ce6 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h @@ -225,6 +225,7 @@ class BrowserProcessImpl : public BrowserProcess, diff --git a/patches/chrome-browser-download-download_item_model.h.patch b/patches/chrome-browser-download-download_item_model.h.patch index 060e6991041f..e9efa78b8512 100644 --- a/patches/chrome-browser-download-download_item_model.h.patch +++ b/patches/chrome-browser-download-download_item_model.h.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h -index 7f3dd3c143d871b06156cfcc58311b9d54db5f2e..42013cafdf69fe00e3db413e9bfe9eaf71bc0b28 100644 +index 91d804ffc56a5fd886e08671efde0ebac77edf1f..bd2081d56fe1cba2d3609967c76981d193e9e94f 100644 --- a/chrome/browser/download/download_item_model.h +++ b/chrome/browser/download/download_item_model.h -@@ -143,6 +143,7 @@ class DownloadItemModel : public DownloadUIModel, +@@ -144,6 +144,7 @@ class DownloadItemModel : public DownloadUIModel, void OnDownloadDestroyed(download::DownloadItem* download) override; private: diff --git a/patches/chrome-browser-download-download_target_determiner.cc.patch b/patches/chrome-browser-download-download_target_determiner.cc.patch index 6be59020703d..4b90dc6b5dbe 100644 --- a/patches/chrome-browser-download-download_target_determiner.cc.patch +++ b/patches/chrome-browser-download-download_target_determiner.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc -index 4aa1c174727044c92f8bf772c49c17d162d4dc25..d02a39cf83cd6e421f0642b981f10b4b6b4688dc 100644 +index e1364680133e0ad91167fd7977a660208a03a788..9716f3d44e959e0989b0cee8ae7592b290be1777 100644 --- a/chrome/browser/download/download_target_determiner.cc +++ b/chrome/browser/download/download_target_determiner.cc -@@ -1256,6 +1256,7 @@ DownloadFileType::DangerLevel DownloadTargetDeterminer::GetDangerLevel( +@@ -1259,6 +1259,7 @@ DownloadFileType::DangerLevel DownloadTargetDeterminer::GetDangerLevel( // contains malware. if (HasPromptedForPath() || confirmation_reason_ != DownloadConfirmationReason::NONE || @@ -10,7 +10,7 @@ index 4aa1c174727044c92f8bf772c49c17d162d4dc25..d02a39cf83cd6e421f0642b981f10b4b !download_->GetForcedFilePath().empty()) return DownloadFileType::NOT_DANGEROUS; -@@ -1294,6 +1295,7 @@ DownloadFileType::DangerLevel DownloadTargetDeterminer::GetDangerLevel( +@@ -1297,6 +1298,7 @@ DownloadFileType::DangerLevel DownloadTargetDeterminer::GetDangerLevel( ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) != 0 || (download_->HasUserGesture() && visits == VISITED_REFERRER))) return DownloadFileType::NOT_DANGEROUS; diff --git a/patches/chrome-browser-extensions-BUILD.gn.patch b/patches/chrome-browser-extensions-BUILD.gn.patch index 76657cf62270..7a65d07db9e4 100644 --- a/patches/chrome-browser-extensions-BUILD.gn.patch +++ b/patches/chrome-browser-extensions-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn -index 913a49367abcca1523a782d248a454166b984f97..e545ac85598e11b195c9409d05641b1e5c30cc0e 100644 +index 690a5ddf57d67bc39c109ee1ebf0ac0979e9fc93..f582edd32d0ca908d948032b7f70010196b4c9a6 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn -@@ -1402,6 +1402,7 @@ static_library("extensions") { +@@ -1416,6 +1416,7 @@ static_library("extensions") { } else { sources += [ "api/braille_display_private/braille_controller_stub.cc" ] } diff --git a/patches/chrome-browser-extensions-api-developer_private-extension_info_generator.cc.patch b/patches/chrome-browser-extensions-api-developer_private-extension_info_generator.cc.patch index 4c049e5b3dc7..1035b9c094ef 100644 --- a/patches/chrome-browser-extensions-api-developer_private-extension_info_generator.cc.patch +++ b/patches/chrome-browser-extensions-api-developer_private-extension_info_generator.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc -index ad388123c6548a639b7efa35e8404dda53915684..2ac0a421f379938208020893ec63edcc0d1aec4d 100644 +index 74a1d670662ff81389d547a2a5521cd1872d657b..1276ae22389bc0197912cf193f5b255f1320a547 100644 --- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc +++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc -@@ -643,6 +643,7 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( +@@ -661,6 +661,7 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( info->incognito_access.is_enabled = util::CanBeIncognitoEnabled(&extension); info->incognito_access.is_active = util::IsIncognitoEnabled(extension.id(), browser_context_); diff --git a/patches/chrome-browser-extensions-extension_management.cc.patch b/patches/chrome-browser-extensions-extension_management.cc.patch index 8f3fcac425c1..957c2c5cbd58 100644 --- a/patches/chrome-browser-extensions-extension_management.cc.patch +++ b/patches/chrome-browser-extensions-extension_management.cc.patch @@ -1,12 +1,12 @@ diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc -index 632f7a2b4101faa596992d6c2154aabd305dcf46..61d8fe87c9e81d600c3d1517006c193271990f68 100644 +index cc2802dfaea85ecc71aa3f387cb1b96364baca93..24768c9b75789167dc6f463e0068aeae7962196b 100644 --- a/chrome/browser/extensions/extension_management.cc +++ b/chrome/browser/extensions/extension_management.cc -@@ -938,6 +938,7 @@ KeyedService* ExtensionManagementFactory::BuildServiceInstanceFor( +@@ -939,6 +939,7 @@ ExtensionManagementFactory::BuildServiceInstanceForBrowserContext( content::BrowserContext* context) const { TRACE_EVENT0("browser,startup", "ExtensionManagementFactory::BuildServiceInstanceFor"); + BRAVE_EXTENSION_MANAGEMENT_FACTORY_BUILD_SERVICE_INSTANCE_FOR - return new ExtensionManagement(Profile::FromBrowserContext(context)); + return std::make_unique( + Profile::FromBrowserContext(context)); } - diff --git a/patches/chrome-browser-extensions-extension_tab_util.cc.patch b/patches/chrome-browser-extensions-extension_tab_util.cc.patch index 2cfb3e15f1cf..aefa709f7664 100644 --- a/patches/chrome-browser-extensions-extension_tab_util.cc.patch +++ b/patches/chrome-browser-extensions-extension_tab_util.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc -index 8bb7f129cc9affbaac244097351f8a2b90d90919..9eef77b6b2b4c99ce1d2f63c4973c68d164ddf20 100644 +index 56ffb7fc1c9d44c8d04d66812f33945fc71cf7ef..022ca2ac0f2308f752d6abffc72853b07c35f258 100644 --- a/chrome/browser/extensions/extension_tab_util.cc +++ b/chrome/browser/extensions/extension_tab_util.cc -@@ -805,6 +805,7 @@ bool ExtensionTabUtil::IsKillURL(const GURL& url) { +@@ -804,6 +804,7 @@ bool ExtensionTabUtil::IsKillURL(const GURL& url) { } if (!url.SchemeIs(content::kChromeUIScheme)) { diff --git a/patches/chrome-browser-flags-BUILD.gn.patch b/patches/chrome-browser-flags-BUILD.gn.patch index 6e2afdfda736..828293255205 100644 --- a/patches/chrome-browser-flags-BUILD.gn.patch +++ b/patches/chrome-browser-flags-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/flags/BUILD.gn b/chrome/browser/flags/BUILD.gn -index b82191200961c5cadc81dca83b0600cea1072bc6..5d15920b6bce55f771b493927cfb87f865a171ce 100644 +index dc6a77d26c9cc79354d296872607070e4107e756..cee8e40e6380df71c4957771b95b3ed395114b2c 100644 --- a/chrome/browser/flags/BUILD.gn +++ b/chrome/browser/flags/BUILD.gn @@ -33,6 +33,7 @@ android_library("java") { diff --git a/patches/chrome-browser-global_keyboard_shortcuts_mac.mm.patch b/patches/chrome-browser-global_keyboard_shortcuts_mac.mm.patch index bfd69463f567..42ac1d02524d 100644 --- a/patches/chrome-browser-global_keyboard_shortcuts_mac.mm.patch +++ b/patches/chrome-browser-global_keyboard_shortcuts_mac.mm.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/global_keyboard_shortcuts_mac.mm b/chrome/browser/global_keyboard_shortcuts_mac.mm -index 6c62ab97045c8db9666fe68096ebc7f216680435..c60c0ec280575dd21e8c1eff71226780218145e9 100644 +index bc90493907668cc0224ea4deffb6b5d706b25e14..918f02fad0fbd2eb5e963b4ca178097b0d32661e 100644 --- a/chrome/browser/global_keyboard_shortcuts_mac.mm +++ b/chrome/browser/global_keyboard_shortcuts_mac.mm @@ -149,6 +149,7 @@ const std::vector& GetShortcutsNotPresentInMainMenu() { diff --git a/patches/chrome-browser-importer-importer_list.cc.patch b/patches/chrome-browser-importer-importer_list.cc.patch index 9cffd47f3b13..46f2b4fce42b 100644 --- a/patches/chrome-browser-importer-importer_list.cc.patch +++ b/patches/chrome-browser-importer-importer_list.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/importer/importer_list.cc b/chrome/browser/importer/importer_list.cc -index d31c78f65d2a65907a97bc02d5013d3ddc19eec6..7e651588666ddae715a58f51d3a2da7eac06a849 100644 +index 0919ea2f5abfeff75d485350eb4c7c14f30f1973..7a4a450be6beec9a763da3aeb0a30bbcd7b6f247 100644 --- a/chrome/browser/importer/importer_list.cc +++ b/chrome/browser/importer/importer_list.cc -@@ -163,20 +163,30 @@ std::vector DetectSourceProfilesWorker( +@@ -164,20 +164,30 @@ std::vector DetectSourceProfilesWorker( if (shell_integration::IsFirefoxDefaultBrowser()) { DetectFirefoxProfiles(locale, &profiles); DetectBuiltinWindowsProfiles(&profiles); diff --git a/patches/chrome-browser-net-profile_network_context_service.cc.patch b/patches/chrome-browser-net-profile_network_context_service.cc.patch index 02ff20802b65..6961c7958aab 100644 --- a/patches/chrome-browser-net-profile_network_context_service.cc.patch +++ b/patches/chrome-browser-net-profile_network_context_service.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc -index e45e4487be0a3f2137bae0f4b96980507e4f4204..342c16d67e8f1cffde4e8dfca7146061bfbb3a96 100644 +index fd92bb9a1f148b97d56b2dc205705e0167e40285..24affdde4ead35db523757aaa6289c92e36e7e8d 100644 --- a/chrome/browser/net/profile_network_context_service.cc +++ b/chrome/browser/net/profile_network_context_service.cc -@@ -515,6 +515,7 @@ network::mojom::CTPolicyPtr ProfileNetworkContextService::GetCTPolicy() { +@@ -550,6 +550,7 @@ network::mojom::CTPolicyPtr ProfileNetworkContextService::GetCTPolicy() { std::vector excluded_legacy_spkis( TranslateStringArray(ct_excluded_legacy_spkis)); diff --git a/patches/chrome-browser-net-system_network_context_manager.cc.patch b/patches/chrome-browser-net-system_network_context_manager.cc.patch index cba2b3e29733..b9e7ef081f79 100644 --- a/patches/chrome-browser-net-system_network_context_manager.cc.patch +++ b/patches/chrome-browser-net-system_network_context_manager.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc -index 0f33b0c21ece0a13c746c4a12eb55a875d87ebe5..a68cdc51f3da332cd3ea53ff5a7cafd0f6ee358c 100644 +index 79914e85fd22de30832348cc07918d56ff15a9d6..5339ee2386c42de33fe71f9e68f04754db7321fd 100644 --- a/chrome/browser/net/system_network_context_manager.cc +++ b/chrome/browser/net/system_network_context_manager.cc -@@ -347,7 +347,7 @@ class SystemNetworkContextManager::URLLoaderFactoryForSystem +@@ -346,7 +346,7 @@ class SystemNetworkContextManager::URLLoaderFactoryForSystem if (!manager_) return; manager_->GetURLLoaderFactory()->CreateLoaderAndStart( diff --git a/patches/chrome-browser-prefs-browser_prefs.cc.patch b/patches/chrome-browser-prefs-browser_prefs.cc.patch index 656a7fe16e37..5c4cdec5c60a 100644 --- a/patches/chrome-browser-prefs-browser_prefs.cc.patch +++ b/patches/chrome-browser-prefs-browser_prefs.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc -index 1944adea64d4cd10e6d70f69f3ad193b524669e0..9d21d29b3b9d342ca603efb38d7983b893da7f62 100644 +index 327282bd867852c8bb974e7ce0100df3cb44d489..bbb955d2438adf1d2f55c55ac290f5e19750809a 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc -@@ -1626,6 +1626,8 @@ void RegisterLocalState(PrefRegistrySimple* registry) { +@@ -1521,6 +1521,8 @@ void RegisterLocalState(PrefRegistrySimple* registry) { DeviceOAuth2TokenStoreDesktop::RegisterPrefs(registry); #endif @@ -11,10 +11,10 @@ index 1944adea64d4cd10e6d70f69f3ad193b524669e0..9d21d29b3b9d342ca603efb38d7983b8 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) screen_ai::RegisterLocalStatePrefs(registry); #endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) -@@ -2036,6 +2038,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry, - #if BUILDFLAG(IS_CHROMEOS_ASH) - registry->RegisterBooleanPref(kClearUserDataDir1Pref, false); +@@ -1935,6 +1937,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry, #endif + + registry->RegisterBooleanPref(prefs::kBlockTruncatedCookies, true); + brave::RegisterProfilePrefs(registry); } diff --git a/patches/chrome-browser-profiles-profile_avatar_icon_util.cc.patch b/patches/chrome-browser-profiles-profile_avatar_icon_util.cc.patch index 411c4f082fc7..db8dcd69b39d 100644 --- a/patches/chrome-browser-profiles-profile_avatar_icon_util.cc.patch +++ b/patches/chrome-browser-profiles-profile_avatar_icon_util.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/profiles/profile_avatar_icon_util.cc b/chrome/browser/profiles/profile_avatar_icon_util.cc -index 4d7ca212d6dd7b42131d4558b5ac17d0c3bc6455..f36de08edb8b95849edb3e5de76ea27e7769ba3c 100644 +index a8d0bc968d2e5fa55cb44a1ae01c4990c3303cd4..1aaf7d834cd107eac8dec2e9ec891e4a859c3bff 100644 --- a/chrome/browser/profiles/profile_avatar_icon_util.cc +++ b/chrome/browser/profiles/profile_avatar_icon_util.cc @@ -276,7 +276,7 @@ constexpr size_t kDefaultAvatarIconsCount = 1; diff --git a/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch b/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch index 0f3e95359412..5f7638503702 100644 --- a/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch +++ b/patches/chrome-browser-renderer_context_menu-render_view_context_menu.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc -index b3e367b9ea823627814922f39d5d14ced31413b3..6a771e3d5a51a4d83925699ef1fdb8b51f9ddbcc 100644 +index fb518bf28000c8218c6f2b50a35f4408567a1134..dfc23a322915558ada98a43ca1e7ab96741ccffc 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc -@@ -2137,6 +2137,7 @@ void RenderViewContextMenu::AppendSearchProvider() { +@@ -2179,6 +2179,7 @@ void RenderViewContextMenu::AppendSearchProvider() { selection_navigation_url_ = match.destination_url; if (!selection_navigation_url_.is_valid()) return; diff --git a/patches/chrome-browser-renderer_context_menu-render_view_context_menu.h.patch b/patches/chrome-browser-renderer_context_menu-render_view_context_menu.h.patch index 1e8f322362d2..c7a984ee47ef 100644 --- a/patches/chrome-browser-renderer_context_menu-render_view_context_menu.h.patch +++ b/patches/chrome-browser-renderer_context_menu-render_view_context_menu.h.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h -index 88034ab23482766ea9483cc0e9a92e0742d48832..8af532121329c9e93f6fd04b0be6c02ef6846486 100644 +index b74da355c7b6b9ec674aef6f3cb69c24423d58a8..a8ed7750c7786239aca08378e8ae3362da6fc06d 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.h +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h @@ -191,6 +191,7 @@ class RenderViewContextMenu diff --git a/patches/chrome-browser-resources-downloads-manager.html.patch b/patches/chrome-browser-resources-downloads-manager.html.patch index ee67ca273b77..d58a5a5cf6bb 100644 --- a/patches/chrome-browser-resources-downloads-manager.html.patch +++ b/patches/chrome-browser-resources-downloads-manager.html.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/downloads/manager.html b/chrome/browser/resources/downloads/manager.html -index 7e1005946e88828d821cced82c3376b709aae7b9..548f0cfb12703ac4dc8b6eb00ff807a921f5d558 100644 +index 5d6ece79a3ee67c9e3f1f08655fa2a717e3eab8f..9263f9b90c539d35e05c8c66534974009469a083 100644 --- a/chrome/browser/resources/downloads/manager.html +++ b/chrome/browser/resources/downloads/manager.html @@ -1,4 +1,4 @@ diff --git a/patches/chrome-browser-resources-extensions-item_list.ts.patch b/patches/chrome-browser-resources-extensions-item_list.ts.patch index 955e1719dec9..092fb29d07a3 100644 --- a/patches/chrome-browser-resources-extensions-item_list.ts.patch +++ b/patches/chrome-browser-resources-extensions-item_list.ts.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/resources/extensions/item_list.ts b/chrome/browser/resources/extensions/item_list.ts -index 6d6862a0ef20c8b88d3f1d0055bfb7df0d41c4c1..6792e05cbec9985f5b1f5c30dd1fc064d1fe2fd2 100644 +index 4b121dbace39b1215bf80f28f2f91249263f7bc3..31cc2e1be554e34a747e5b4cfb5fc8eb800b9196 100644 --- a/chrome/browser/resources/extensions/item_list.ts +++ b/chrome/browser/resources/extensions/item_list.ts -@@ -14,6 +14,7 @@ import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bu +@@ -15,6 +15,7 @@ import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bu import {ExtensionsItemElement, ItemDelegate} from './item.js'; import {getTemplate} from './item_list.html.js'; diff --git a/patches/chrome-browser-resources-history-history_item.html.patch b/patches/chrome-browser-resources-history-history_item.html.patch index 6644c9762980..36c9645ba157 100644 --- a/patches/chrome-browser-resources-history-history_item.html.patch +++ b/patches/chrome-browser-resources-history-history_item.html.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/history/history_item.html b/chrome/browser/resources/history/history_item.html -index f9ac90980b472ba15b2883591c15d67b9aa20d33..d23c8d26771a719deb112d665ed80188ffac0f46 100644 +index 92a190f5988c8495e032f5553c19fce2809033b5..bc17c2eff898eddf0b2be0ccc919cd650bd04cfe 100644 --- a/chrome/browser/resources/history/history_item.html +++ b/chrome/browser/resources/history/history_item.html @@ -1,4 +1,4 @@ diff --git a/patches/chrome-browser-resources-history-history_item.ts.patch b/patches/chrome-browser-resources-history-history_item.ts.patch index 1d5a231e6a10..4fbbf29385bd 100644 --- a/patches/chrome-browser-resources-history-history_item.ts.patch +++ b/patches/chrome-browser-resources-history-history_item.ts.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/history/history_item.ts b/chrome/browser/resources/history/history_item.ts -index 0471073ec09e22680a69334400e466c1da43dfdf..450cddaee745bfcbff6231aabf64e097c2d2a91e 100644 +index 30dd315c827ecbdcbf6c87738aa3b93635b35d6e..63219697dbd1d221b3ec9482cf6d4082bd663683 100644 --- a/chrome/browser/resources/history/history_item.ts +++ b/chrome/browser/resources/history/history_item.ts @@ -9,6 +9,7 @@ import 'chrome://resources/cr_elements/cr_icons.css.js'; diff --git a/patches/chrome-browser-resources-password_manager-BUILD.gn.patch b/patches/chrome-browser-resources-password_manager-BUILD.gn.patch index ed1bca533fa2..bfbf8855f2db 100644 --- a/patches/chrome-browser-resources-password_manager-BUILD.gn.patch +++ b/patches/chrome-browser-resources-password_manager-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/resources/password_manager/BUILD.gn b/chrome/browser/resources/password_manager/BUILD.gn -index 677c2e90e2b74fce4098f8ae29dadcdcbe9e312b..6d32518dec00ee96c4cc6d8a4c707eee1b482aeb 100644 +index 6c4b33d9b7db616970af5a7fdd786aa3f9cb76cc..f909ecc6b36716704ad7b8939791646e82fb2a71 100644 --- a/chrome/browser/resources/password_manager/BUILD.gn +++ b/chrome/browser/resources/password_manager/BUILD.gn -@@ -134,4 +134,5 @@ build_webui("build") { +@@ -136,4 +136,5 @@ build_webui("build") { "$root_gen_dir/chrome/browser/resources/settings_shared/tsc", root_build_dir) ] } diff --git a/patches/chrome-browser-resources-settings-BUILD.gn.patch b/patches/chrome-browser-resources-settings-BUILD.gn.patch index 19e1cdb8c77e..b44524ab8f4f 100644 --- a/patches/chrome-browser-resources-settings-BUILD.gn.patch +++ b/patches/chrome-browser-resources-settings-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn -index e37a0086c59da1c03f3ad0339add090a597b8ec7..445ba9768978e637627dc93d90871f6ede127eee 100644 +index 6b484992fb3ffdaf5128aa8a29fbf6a408513308..975eac76efad9b21bb6286ebee707b62361aea3f 100644 --- a/chrome/browser/resources/settings/BUILD.gn +++ b/chrome/browser/resources/settings/BUILD.gn -@@ -437,4 +437,5 @@ build_webui("build") { +@@ -443,4 +443,5 @@ build_webui("build") { "$root_gen_dir/chrome/browser/resources/settings_shared/tsc", root_build_dir) ] } diff --git a/patches/chrome-browser-resources-settings-people_page-sync_controls.ts.patch b/patches/chrome-browser-resources-settings-people_page-sync_controls.ts.patch index 77fe4d47677a..ac2540a4d6fb 100644 --- a/patches/chrome-browser-resources-settings-people_page-sync_controls.ts.patch +++ b/patches/chrome-browser-resources-settings-people_page-sync_controls.ts.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/settings/people_page/sync_controls.ts b/chrome/browser/resources/settings/people_page/sync_controls.ts -index d9cecedc93ded3eecb1913c81710ed4470b94209..a0bbf205aee9291f6f9b34a451091420b38a1d9a 100644 +index ffe9ddb3fba014e6a3a3004adf2c90247fceba58..f59054290c23ecee210375c1b917143a833551a6 100644 --- a/chrome/browser/resources/settings/people_page/sync_controls.ts +++ b/chrome/browser/resources/settings/people_page/sync_controls.ts @@ -118,7 +118,7 @@ export class SettingsSyncControlsElement extends diff --git a/patches/chrome-browser-resources-settings-privacy_page-privacy_page.html.patch b/patches/chrome-browser-resources-settings-privacy_page-privacy_page.html.patch index 50e5c1551da4..fda03fb24fc0 100644 --- a/patches/chrome-browser-resources-settings-privacy_page-privacy_page.html.patch +++ b/patches/chrome-browser-resources-settings-privacy_page-privacy_page.html.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html -index d1c96ab670f42622b85b0f6aa36091a7cbf968bc..a570cb04efcf88666e9c6e236bda9798fbcade66 100644 +index 9072306bbf4fdba5a0a0aa37b4ccebee0c1ff33e..f028873838d4ba5010c35306b49bd4af11fed902 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html @@ -34,6 +34,7 @@ diff --git a/patches/chrome-browser-resources-settings-privacy_page-privacy_page.ts.patch b/patches/chrome-browser-resources-settings-privacy_page-privacy_page.ts.patch index 5f1fd104dae8..ec6d533635f0 100644 --- a/patches/chrome-browser-resources-settings-privacy_page-privacy_page.ts.patch +++ b/patches/chrome-browser-resources-settings-privacy_page-privacy_page.ts.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts -index 76c7d5d0170355daab2a4546da607bf8201af4eb..f7995ceef9a04b10a02f38af07b530d4b815ed4b 100644 +index f063fa13689e802d0dfc642dbc601b0d74cc11c3..116326c6e4304cadac3bd027a76e0d600ca4300f 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts @@ -18,6 +18,7 @@ import '../settings_page/settings_animated_pages.js'; diff --git a/patches/chrome-browser-resources-settings-route.ts.patch b/patches/chrome-browser-resources-settings-route.ts.patch index 0d794f23fd7f..838c1c5fa90d 100644 --- a/patches/chrome-browser-resources-settings-route.ts.patch +++ b/patches/chrome-browser-resources-settings-route.ts.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts -index f0b4905379d30a14a937b2212c1d2caa8ef50704..114423bb60359171053c1a94e1bc4660e3bd4ae3 100644 +index 82631548e92c7b11cb0c1bfb673a809b11f3de00..06bb35a2710b0b070a3f910acc882ec231fbcaeb 100644 --- a/chrome/browser/resources/settings/route.ts +++ b/chrome/browser/resources/settings/route.ts @@ -8,6 +8,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; @@ -10,7 +10,7 @@ index f0b4905379d30a14a937b2212c1d2caa8ef50704..114423bb60359171053c1a94e1bc4660 /** * Add all of the child routes that originate from the privacy route, * regardless of whether the privacy section under basic or advanced. -@@ -278,6 +279,7 @@ function createBrowserSettingsRoutes(): SettingsRoutes { +@@ -283,6 +284,7 @@ function createBrowserSettingsRoutes(): SettingsRoutes { } // } diff --git a/patches/chrome-browser-resources-settings-router.ts.patch b/patches/chrome-browser-resources-settings-router.ts.patch index 60203fc04212..23e1df1af082 100644 --- a/patches/chrome-browser-resources-settings-router.ts.patch +++ b/patches/chrome-browser-resources-settings-router.ts.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/resources/settings/router.ts b/chrome/browser/resources/settings/router.ts -index 18d787f7f1a13b7a903021598c442a5147f19cc1..38d83dde5ee1f7b8f783f34994aaf61fc91400fb 100644 +index 490064371b6b57236724ec0919a4d549a5ab2c9e..965028df2b0ea8cd675214371ae88ddb1a713f90 100644 --- a/chrome/browser/resources/settings/router.ts +++ b/chrome/browser/resources/settings/router.ts -@@ -101,6 +101,7 @@ export interface SettingsRoutes { +@@ -102,6 +102,7 @@ export interface SettingsRoutes { SYNC_ADVANCED: Route; SYSTEM: Route; TRIGGERED_RESET_DIALOG: Route; diff --git a/patches/chrome-browser-resources-settings-site_settings-constants.ts.patch b/patches/chrome-browser-resources-settings-site_settings-constants.ts.patch index 22a33d6dd5f9..f985b4276a2b 100644 --- a/patches/chrome-browser-resources-settings-site_settings-constants.ts.patch +++ b/patches/chrome-browser-resources-settings-site_settings-constants.ts.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/resources/settings/site_settings/constants.ts b/chrome/browser/resources/settings/site_settings/constants.ts -index 42a580a7eed0f49fc7251ef867c721a04a37d0bf..00331b98d9bd28c9ab11373b52edc4bd2a35d742 100644 +index 81acd993d10b96b5edb57d566197967696973d4f..c923b663a75bcd505a9d56e4b0bd3a5cfe283a2f 100644 --- a/chrome/browser/resources/settings/site_settings/constants.ts +++ b/chrome/browser/resources/settings/site_settings/constants.ts -@@ -53,6 +53,7 @@ export enum ContentSettingsTypes { +@@ -54,6 +54,7 @@ export enum ContentSettingsTypes { // are used everywhere where ContentSettingsTypes is used in JS. PDF_DOCUMENTS = 'pdfDocuments', SITE_DATA = 'site-data', diff --git a/patches/chrome-browser-resources-settings-site_settings-settings_category_default_radio_group.ts.patch b/patches/chrome-browser-resources-settings-site_settings-settings_category_default_radio_group.ts.patch index 36a13c4f33c5..893af44f0dac 100644 --- a/patches/chrome-browser-resources-settings-site_settings-settings_category_default_radio_group.ts.patch +++ b/patches/chrome-browser-resources-settings-site_settings-settings_category_default_radio_group.ts.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts -index 8c7966f45bdf471a5809fecc9bc24cba0abf498e..0d093d6d07c978ec0e083e1018bd78353e3ca63f 100644 +index 30a5a05854db15351c292ec28ba8ea422efed16f..16c3add479c09abd7f47ef6de0e0879a00097e47 100644 --- a/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts +++ b/chrome/browser/resources/settings/site_settings/settings_category_default_radio_group.ts -@@ -158,6 +158,7 @@ export class SettingsCategoryDefaultRadioGroupElement extends +@@ -159,6 +159,7 @@ export class SettingsCategoryDefaultRadioGroupElement extends case ContentSettingsTypes.WINDOW_MANAGEMENT: // "Ask" vs "Blocked". return ContentSetting.ASK; diff --git a/patches/chrome-browser-resources-settings-site_settings_page-site_settings_page.ts.patch b/patches/chrome-browser-resources-settings-site_settings_page-site_settings_page.ts.patch index 212dc780bb11..90b4edf3b1ab 100644 --- a/patches/chrome-browser-resources-settings-site_settings_page-site_settings_page.ts.patch +++ b/patches/chrome-browser-resources-settings-site_settings_page-site_settings_page.ts.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts -index e06784e40d55666b75bb3e4207ce55366cb9c84b..415f8966d3175fa012728855719b89d5d831d175 100644 +index 6b3fcd5a1d53b56ad69aecddf96108d3c26782ee..eded10a7e6959b5ad4219601ea0a70e115fbe262 100644 --- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts +++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.ts @@ -8,6 +8,7 @@ diff --git a/patches/chrome-browser-resources-signin-profile_picker-profile_picker_main_view.ts.patch b/patches/chrome-browser-resources-signin-profile_picker-profile_picker_main_view.ts.patch index e774767d8d8e..779b7118590d 100644 --- a/patches/chrome-browser-resources-signin-profile_picker-profile_picker_main_view.ts.patch +++ b/patches/chrome-browser-resources-signin-profile_picker-profile_picker_main_view.ts.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts -index a784f86abf49545002b951a890a4416a6f26b614..fae8a847f091a4a5807833b032aaa5211530431d 100644 +index 55a1def4837a4ebdbc9eb9b243e1ea4d63257a0c..332b32aa1f01e4e2463e07142742be6e20ed942b 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts +++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.ts @@ -101,6 +101,7 @@ export class ProfilePickerMainViewElement extends diff --git a/patches/chrome-browser-safe_browsing-download_protection-check_client_download_request_base.cc.patch b/patches/chrome-browser-safe_browsing-download_protection-check_client_download_request_base.cc.patch index 8342cdd6f2f3..b7ede7612d9d 100644 --- a/patches/chrome-browser-safe_browsing-download_protection-check_client_download_request_base.cc.patch +++ b/patches/chrome-browser-safe_browsing-download_protection-check_client_download_request_base.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc -index bc867180d9429702b7613a3c2f7789949c936ea1..0e418fcf8b5782f81733f89b8433fe47815b2068 100644 +index 00cc4207beb9c52ddae74de95fc18ee059eaf16a..b434f9536f155f2bd75cab6abe9a20a80ecc4d43 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc @@ -290,6 +290,7 @@ void CheckClientDownloadRequestBase::OnRequestBuilt( diff --git a/patches/chrome-browser-sync-sync_service_factory.cc.patch b/patches/chrome-browser-sync-sync_service_factory.cc.patch index dc293121fb5b..d922203fe64f 100644 --- a/patches/chrome-browser-sync-sync_service_factory.cc.patch +++ b/patches/chrome-browser-sync-sync_service_factory.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/sync/sync_service_factory.cc b/chrome/browser/sync/sync_service_factory.cc -index b86e3e287da427eb01465fba438e5c54a0e49799..5444ccfdc3c8e9f72cb88ef735f326c83ecf8608 100644 +index a8f5898effb1294a62ffc75adab5b189395401b3..cacfacd7bd318e9208b69e34733fc6ccbd433f0f 100644 --- a/chrome/browser/sync/sync_service_factory.cc +++ b/chrome/browser/sync/sync_service_factory.cc -@@ -170,7 +170,7 @@ std::unique_ptr BuildSyncService( +@@ -172,7 +172,7 @@ std::unique_ptr BuildSyncService( } auto sync_service = diff --git a/patches/chrome-browser-ui-BUILD.gn.patch b/patches/chrome-browser-ui-BUILD.gn.patch index 96abe7bd4d1b..f8e3e022e39b 100644 --- a/patches/chrome-browser-ui-BUILD.gn.patch +++ b/patches/chrome-browser-ui-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn -index 8ffa857f767e88ade3a2ef8f92a1aa05a9f0d032..bf05c1b027ece40fe2b3f6ea96d3cfb49a5d9a31 100644 +index aaaab0d2783adefa79b439de943579b4652689da..3f3a6c870f4a05da860be0ea599422d4ebe23eb3 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn -@@ -694,6 +694,7 @@ static_library("ui") { +@@ -698,6 +698,7 @@ static_library("ui") { "//chrome/browser/profiling_host", "//chrome/browser/ui/webui:configs", ] @@ -10,7 +10,7 @@ index 8ffa857f767e88ade3a2ef8f92a1aa05a9f0d032..bf05c1b027ece40fe2b3f6ea96d3cfb4 if (enable_vr && is_win) { deps += [ "//chrome/browser/vr:vr_base" ] -@@ -4298,10 +4299,13 @@ static_library("ui") { +@@ -4346,10 +4347,13 @@ static_library("ui") { ] deps += [ "//chrome/updater/app/server/win:updater_legacy_idl_idl" ] } else { diff --git a/patches/chrome-browser-ui-android-toolbar-BUILD.gn.patch b/patches/chrome-browser-ui-android-toolbar-BUILD.gn.patch index 653e90635be5..5e6a49b372a4 100644 --- a/patches/chrome-browser-ui-android-toolbar-BUILD.gn.patch +++ b/patches/chrome-browser-ui-android-toolbar-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn -index 74a50a599c2a5af1508e449a67be91adc7b865e1..3bc269d5c78fc376e9a557855e056f2b84548ea4 100644 +index 1562440ac47d0b6834a5ecac0c8988ae136767e7..08bba4685ffa3547e56edeebba135dfd19efeb0b 100644 --- a/chrome/browser/ui/android/toolbar/BUILD.gn +++ b/chrome/browser/ui/android/toolbar/BUILD.gn @@ -116,6 +116,7 @@ android_library("java") { diff --git a/patches/chrome-browser-ui-android-toolbar-java-res-layout-toolbar_phone.xml.patch b/patches/chrome-browser-ui-android-toolbar-java-res-layout-toolbar_phone.xml.patch index e5644447fa18..0718a1994f3d 100644 --- a/patches/chrome-browser-ui-android-toolbar-java-res-layout-toolbar_phone.xml.patch +++ b/patches/chrome-browser-ui-android-toolbar-java-res-layout-toolbar_phone.xml.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml -index 5206cf656362017f258b7843c4522eb8a302fbdd..3f03586cfdc4cab4d5740b700bf8e31ae0ac3880 100644 +index 8b7485b11005399cecf57537a8a58961084b7b29..9c45f14e1aca14331b8c2b6e8873dbfce78037ff 100644 --- a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml +++ b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_phone.xml @@ -38,6 +38,7 @@ found in the LICENSE file. @@ -10,10 +10,10 @@ index 5206cf656362017f258b7843c4522eb8a302fbdd..3f03586cfdc4cab4d5740b700bf8e31a android:layout_gravity="top|end" android:focusable="true" android:focusableInTouchMode="true"> -@@ -49,6 +50,7 @@ found in the LICENSE file. - android:visibility="gone" +@@ -50,6 +51,7 @@ found in the LICENSE file. android:layout_width="52dp" - style="@style/ToolbarButton" /> + style="@style/ToolbarHoverableButton" /> + + (this)), diff --git a/patches/chrome-browser-ui-browser_navigator.cc.patch b/patches/chrome-browser-ui-browser_navigator.cc.patch index 3ef49c00ec23..bf1f376d77d2 100644 --- a/patches/chrome-browser-ui-browser_navigator.cc.patch +++ b/patches/chrome-browser-ui-browser_navigator.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc -index 88edd87bcb2d0bb6eb0cb2d9d9b281d6655cbb18..b5a0d463a89522fc953a96ceb0420a8843bc2e62 100644 +index 3b7f96e505e0ba32837b83be5473562e3e120452..b4433a1fd9b008741a0ef9d6e9d75405d93a0287 100644 --- a/chrome/browser/ui/browser_navigator.cc +++ b/chrome/browser/ui/browser_navigator.cc -@@ -590,6 +590,7 @@ base::WeakPtr Navigate(NavigateParams* params) { +@@ -585,6 +585,7 @@ base::WeakPtr Navigate(NavigateParams* params) { // Block any navigation requests in locked fullscreen mode. return nullptr; } @@ -10,7 +10,7 @@ index 88edd87bcb2d0bb6eb0cb2d9d9b281d6655cbb18..b5a0d463a89522fc953a96ceb0420a88 // Open System Apps in their standalone window if necessary. // TODO(crbug.com/1096345): Remove this code after we integrate with intent -@@ -912,6 +913,7 @@ bool IsHostAllowedInIncognito(const GURL& url) { +@@ -922,6 +923,7 @@ bool IsHostAllowedInIncognito(const GURL& url) { base::StringPiece host = url.host_piece(); if (scheme != content::kChromeUIScheme) return true; diff --git a/patches/chrome-browser-ui-browser_ui_prefs.cc.patch b/patches/chrome-browser-ui-browser_ui_prefs.cc.patch index 7bfb138221ad..25e926d4cc4f 100644 --- a/patches/chrome-browser-ui-browser_ui_prefs.cc.patch +++ b/patches/chrome-browser-ui-browser_ui_prefs.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc -index 28732e323ec2e105bcd6675e9e339d8343f21c86..e3c6a53062a02a3b16f445b8d8ab634a0c4e09ba 100644 +index 1d312986c62def1b09ca502e02d755b56c6cdcb0..8e9b4707b730fb1f1bd060bb109bfba2b59488c5 100644 --- a/chrome/browser/ui/browser_ui_prefs.cc +++ b/chrome/browser/ui/browser_ui_prefs.cc -@@ -78,7 +78,7 @@ void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) { +@@ -83,7 +83,7 @@ void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true); registry->RegisterBooleanPref( translate::prefs::kOfferTranslateEnabled, true, @@ -10,4 +10,4 @@ index 28732e323ec2e105bcd6675e9e339d8343f21c86..e3c6a53062a02a3b16f445b8d8ab634a + user_prefs::PrefRegistrySyncable::NO_REGISTRATION_FLAGS); registry->RegisterStringPref(prefs::kCloudPrintEmail, std::string()); registry->RegisterBooleanPref(prefs::kCloudPrintProxyEnabled, true); - registry->RegisterBooleanPref(prefs::kCloudPrintSubmitEnabled, true); + registry->RegisterDictionaryPref(prefs::kBrowserWindowPlacement); diff --git a/patches/chrome-browser-ui-chrome_pages.cc.patch b/patches/chrome-browser-ui-chrome_pages.cc.patch index 7aeac58fc15f..e95e94b420ba 100644 --- a/patches/chrome-browser-ui-chrome_pages.cc.patch +++ b/patches/chrome-browser-ui-chrome_pages.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc -index b36ca5df10936fa6972d1e41adc769b0ad7a0b06..3ea029a73dee70ff8e3f5d678899fadfbd205f99 100644 +index 69bf9d2f105c6f4d0ad8d2be2ac60b3640fb53b9..fe5dd5f83ce2be38eafaa26e176122c56cee9acc 100644 --- a/chrome/browser/ui/chrome_pages.cc +++ b/chrome/browser/ui/chrome_pages.cc -@@ -344,7 +344,7 @@ void ShowSlow(Browser* browser) { +@@ -356,7 +356,7 @@ void ShowSlow(Browser* browser) { #endif } diff --git a/patches/chrome-browser-ui-cocoa-main_menu_builder.mm.patch b/patches/chrome-browser-ui-cocoa-main_menu_builder.mm.patch index 0f71719b0250..6056d203ff28 100644 --- a/patches/chrome-browser-ui-cocoa-main_menu_builder.mm.patch +++ b/patches/chrome-browser-ui-cocoa-main_menu_builder.mm.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/cocoa/main_menu_builder.mm b/chrome/browser/ui/cocoa/main_menu_builder.mm -index 698dc218f583dd0516f2deb386e2f0befa1290ef..6562e010879266b137bb57845aaf75da8259d2f3 100644 +index bcf4697bb530e67efc0482c01d5c0c5c0a3ce1f7..a531b87b66842de087bbfa6e8613ca4a27f7f9c5 100644 --- a/chrome/browser/ui/cocoa/main_menu_builder.mm +++ b/chrome/browser/ui/cocoa/main_menu_builder.mm @@ -109,6 +109,7 @@ NSMenuItem* BuildFileMenu(NSApplication* nsapp, diff --git a/patches/chrome-browser-ui-color-BUILD.gn.patch b/patches/chrome-browser-ui-color-BUILD.gn.patch index ec73b7ff5726..5074ecf93325 100644 --- a/patches/chrome-browser-ui-color-BUILD.gn.patch +++ b/patches/chrome-browser-ui-color-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/color/BUILD.gn b/chrome/browser/ui/color/BUILD.gn -index 0b42bdc5e5e818deb52bc7fe5d476401bcbf77e9..245ad0a93320e5bce088bb195d19df2d0a05f567 100644 +index a90f6aabfa63a2ed5805baa1a960eb30ca4e3227..23573e2762fa8fde66323ba080f03b8137eb4821 100644 --- a/chrome/browser/ui/color/BUILD.gn +++ b/chrome/browser/ui/color/BUILD.gn @@ -57,6 +57,7 @@ source_set("mixers") { diff --git a/patches/chrome-browser-ui-dialogs-outdated_upgrade_bubble.cc.patch b/patches/chrome-browser-ui-dialogs-outdated_upgrade_bubble.cc.patch index ef59a716eef3..83463938ce76 100644 --- a/patches/chrome-browser-ui-dialogs-outdated_upgrade_bubble.cc.patch +++ b/patches/chrome-browser-ui-dialogs-outdated_upgrade_bubble.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/dialogs/outdated_upgrade_bubble.cc b/chrome/browser/ui/dialogs/outdated_upgrade_bubble.cc -index ec67e6e18a925718956141ff517d355f81fa8668..0a29aedfd082123e36bd915a0486953894f14315 100644 +index 448eb26ee4fffcbba6b2cc6ebe91c4d4e1cc5707..87f5ec73c863f53c787388767178f49d554ebeb6 100644 --- a/chrome/browser/ui/dialogs/outdated_upgrade_bubble.cc +++ b/chrome/browser/ui/dialogs/outdated_upgrade_bubble.cc @@ -35,6 +35,8 @@ namespace { diff --git a/patches/chrome-browser-ui-tab_helpers.cc.patch b/patches/chrome-browser-ui-tab_helpers.cc.patch index 359173df7a96..5cf5b22c6d0f 100644 --- a/patches/chrome-browser-ui-tab_helpers.cc.patch +++ b/patches/chrome-browser-ui-tab_helpers.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc -index 1ec9817a39d4a15fe1b97d23dd5d0898133756ed..2cf3fa328035d0b7f4d8bab9ecdf081856f98b0a 100644 +index d9f7c6749b8b6a8e33745ead0d0d3650ea6d32eb..433fd078ab8d21349ec5ab58ad68917013a8d660 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc -@@ -743,4 +743,5 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) { +@@ -734,4 +734,5 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) { // This is common code for all of us. PLEASE DO YOUR PART to keep it tidy and // organized. diff --git a/patches/chrome-browser-ui-views-bookmarks-bookmark_bar_view.cc.patch b/patches/chrome-browser-ui-views-bookmarks-bookmark_bar_view.cc.patch index c038c4608ccd..361c17170ec3 100644 --- a/patches/chrome-browser-ui-views-bookmarks-bookmark_bar_view.cc.patch +++ b/patches/chrome-browser-ui-views-bookmarks-bookmark_bar_view.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc -index b2e4d83bbcb482d8e37f12cd8c9a43cca1fa461a..7b2605bfae4a504e29be3efdba3b76a89cc87565 100644 +index faa3c92ab2db22c4c550a2236496ac4d6b8b5d33..686bfe26fd705c8920d8e5fdbcb017a260607206 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc -@@ -1120,6 +1120,7 @@ void BookmarkBarView::Layout() { +@@ -1157,6 +1157,7 @@ void BookmarkBarView::Layout() { x = next_x; } } diff --git a/patches/chrome-browser-ui-views-bookmarks-bookmark_bubble_view.cc.patch b/patches/chrome-browser-ui-views-bookmarks-bookmark_bubble_view.cc.patch index 7ae7fe39db67..58aa042df822 100644 --- a/patches/chrome-browser-ui-views-bookmarks-bookmark_bubble_view.cc.patch +++ b/patches/chrome-browser-ui-views-bookmarks-bookmark_bubble_view.cc.patch @@ -1,10 +1,10 @@ diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc -index 3209a9a3c8e195dc60f2a4920e78751bd781c312..8589b281f6077e814804260b53f91282a23cd188 100644 +index 673f2ed2d0a46b02049864d9da34242dd9c2a264..c91d3ad943f83c7c6b8afc31c8eca9c2e73bdbdc 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc -@@ -411,6 +411,7 @@ void BookmarkBubbleView::ShowBubble( - dialog_model_builder.Build(), anchor_view, - views::BubbleBorder::TOP_RIGHT); +@@ -533,6 +533,7 @@ void BookmarkBubbleView::ShowBubble( + auto bubble = std::make_unique( + std::move(dialog_model), anchor_view, views::BubbleBorder::TOP_RIGHT); bookmark_bubble_ = bubble.get(); + BRAVE_BOOKMARK_BUBBLE_VIEW if (highlighted_button) diff --git a/patches/chrome-browser-ui-views-bubble-webui_bubble_manager.h.patch b/patches/chrome-browser-ui-views-bubble-webui_bubble_manager.h.patch index 823be461378f..880ce3223cff 100644 --- a/patches/chrome-browser-ui-views-bubble-webui_bubble_manager.h.patch +++ b/patches/chrome-browser-ui-views-bubble-webui_bubble_manager.h.patch @@ -1,12 +1,12 @@ diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager.h b/chrome/browser/ui/views/bubble/webui_bubble_manager.h -index 1bccdbfc4895a5aa4f69aaa1b7bc71810d4ac31f..78730cb3abbd2ab7757c0bd9972d6beb396e67be 100644 +index 03554e2aa75c929c6410c4a48c5eee1e68abd89d..dbdd9a226633790f1b1950844a7c7471288b191d 100644 --- a/chrome/browser/ui/views/bubble/webui_bubble_manager.h +++ b/chrome/browser/ui/views/bubble/webui_bubble_manager.h -@@ -165,6 +165,7 @@ class WebUIBubbleManagerT : public WebUIBubbleManager { +@@ -170,6 +170,7 @@ class WebUIBubbleManagerT : public WebUIBubbleManager { auto bubble_view = std::make_unique( anchor_view_, contents_wrapper, anchor, arrow); + BRAVE_WEBUI_BUBBLE_MANAGER_T_CREATE_WEB_UI_BUBBLE_DIALOG - auto weak_ptr = bubble_view->GetWeakPtr(); - views::BubbleDialogDelegateView::CreateBubble(std::move(bubble_view)); - return weak_ptr; + + // Register callback to emit histogram when the widget is created + if (bubble_init_start_time_) { diff --git a/patches/chrome-browser-ui-views-location_bar-icon_label_bubble_view.cc.patch b/patches/chrome-browser-ui-views-location_bar-icon_label_bubble_view.cc.patch index 2ad558182cfa..66850986a0f8 100644 --- a/patches/chrome-browser-ui-views-location_bar-icon_label_bubble_view.cc.patch +++ b/patches/chrome-browser-ui-views-location_bar-icon_label_bubble_view.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc -index 6049b601f448778bdef569622917f205588811ce..cfce6feae9a3ec24e06a2f99a5cd5d48c2fa7820 100644 +index 0afcd7afa8d543e6c8b31054ae049deeefa98aa0..f08fbc0e52431b8b37b5a4befbbecfbacf210383 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc -@@ -651,6 +651,7 @@ SkPath IconLabelBubbleView::GetHighlightPath() const { +@@ -662,6 +662,7 @@ SkPath IconLabelBubbleView::GetHighlightPath() const { const float corner_radius = highlight_bounds.height() / 2.f; const SkRect rect = RectToSkRect(highlight_bounds); diff --git a/patches/chrome-browser-ui-views-location_bar-location_bar_view.cc.patch b/patches/chrome-browser-ui-views-location_bar-location_bar_view.cc.patch index 59d58f733f03..f1639a4c8da7 100644 --- a/patches/chrome-browser-ui-views-location_bar-location_bar_view.cc.patch +++ b/patches/chrome-browser-ui-views-location_bar-location_bar_view.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc -index 83e19c00add9fb15101735925b279aedf45785ce..1fa7b9eb731c1b94d0f88d6f38600485737233aa 100644 +index fb55e66b48bb018ea281333c2541fbf212c527f9..89f95ffba36bd6158c3c91e8c6b1a02249080031 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc -@@ -754,6 +754,7 @@ void LocationBarView::Layout() { +@@ -752,6 +752,7 @@ void LocationBarView::Layout() { } }; diff --git a/patches/chrome-browser-ui-views-location_bar-location_bar_view.h.patch b/patches/chrome-browser-ui-views-location_bar-location_bar_view.h.patch index dcc7775c18fa..e4be63bdae6f 100644 --- a/patches/chrome-browser-ui-views-location_bar-location_bar_view.h.patch +++ b/patches/chrome-browser-ui-views-location_bar-location_bar_view.h.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h -index 6fd3631dc90b578ca1adaef3d69b97611734ebf0..a0ab959e60515842c5b7ee77edf7c822f737dfb7 100644 +index 0e3f3edeff9f3b9132e15dd4a55d9df60a4a0756..eb2b466415a68a98151367b46f1611a88c651827 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h @@ -109,6 +109,7 @@ class LocationBarView : public LocationBar, @@ -10,7 +10,7 @@ index 6fd3631dc90b578ca1adaef3d69b97611734ebf0..a0ab959e60515842c5b7ee77edf7c822 void Init(); // True if this instance has been initialized by calling Init, which can only -@@ -161,6 +162,7 @@ class LocationBarView : public LocationBar, +@@ -162,6 +163,7 @@ class LocationBarView : public LocationBar, // Updates the controller, and, if |contents| is non-null, restores saved // state that the tab holds. @@ -18,7 +18,7 @@ index 6fd3631dc90b578ca1adaef3d69b97611734ebf0..a0ab959e60515842c5b7ee77edf7c822 void Update(content::WebContents* contents); // Clears the location bar's state for |contents|. -@@ -243,6 +245,7 @@ class LocationBarView : public LocationBar, +@@ -244,6 +246,7 @@ class LocationBarView : public LocationBar, std::vector& GetContentSettingViewsForTest() { return content_setting_views_; } diff --git a/patches/chrome-browser-ui-views-page_info-page_info_main_view.cc.patch b/patches/chrome-browser-ui-views-page_info-page_info_main_view.cc.patch deleted file mode 100644 index f8605153da3f..000000000000 --- a/patches/chrome-browser-ui-views-page_info-page_info_main_view.cc.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/chrome/browser/ui/views/page_info/page_info_main_view.cc b/chrome/browser/ui/views/page_info/page_info_main_view.cc -index f076917a8c9135f0c4c8cab129ee73fcbc3527f9..f4bf49cbe475d588f93d53e674657b238347b9d8 100644 ---- a/chrome/browser/ui/views/page_info/page_info_main_view.cc -+++ b/chrome/browser/ui/views/page_info/page_info_main_view.cc -@@ -507,6 +507,7 @@ gfx::Size PageInfoMainView::CalculatePreferredSize() const { - if (site_settings_view_) { - width = std::max(width, site_settings_view_->GetPreferredSize().width()); - width = std::max(width, permissions_view_->GetPreferredSize().width()); -+ BRAVE_PAGE_INFO_MAIN_VIEW_CALCULATE_PREFERRED_SIZE - } - return gfx::Size(width, views::View::GetHeightForWidth(width)); - } diff --git a/patches/chrome-browser-ui-views-page_info-page_info_view_factory.cc.patch b/patches/chrome-browser-ui-views-page_info-page_info_view_factory.cc.patch index 5494e741e39d..1ce034431065 100644 --- a/patches/chrome-browser-ui-views-page_info-page_info_view_factory.cc.patch +++ b/patches/chrome-browser-ui-views-page_info-page_info_view_factory.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.cc b/chrome/browser/ui/views/page_info/page_info_view_factory.cc -index c5a69cea384b4ab55b24dc9e16e499d45b4e1e88..5f09dbaff10ac0c1bc56dabac056972d8c7e8f03 100644 +index 57aa072f005a47373e6e379142d7aba7207d951e..802e419b20e57e23cf9346c3c2de3dec84981f67 100644 --- a/chrome/browser/ui/views/page_info/page_info_view_factory.cc +++ b/chrome/browser/ui/views/page_info/page_info_view_factory.cc @@ -409,6 +409,7 @@ const ui::ImageModel PageInfoViewFactory::GetPermissionIcon( diff --git a/patches/chrome-browser-ui-views-permissions-permission_prompt_bubble_base_view.cc.patch b/patches/chrome-browser-ui-views-permissions-permission_prompt_bubble_base_view.cc.patch index cc2e2ad963a0..848b7580517e 100644 --- a/patches/chrome-browser-ui-views-permissions-permission_prompt_bubble_base_view.cc.patch +++ b/patches/chrome-browser-ui-views-permissions-permission_prompt_bubble_base_view.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc -index d64456f3a768104bc2048af616afc335bbdb41c9..b68661f9f2b72c11992b393480de849dc155a421 100644 +index c2b922df0590d17fd84e2b6c95208fd566da1aef..f8423480cfcaf7cf298be42abf38aa3c851c24c7 100644 --- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc +++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_base_view.cc -@@ -190,6 +190,7 @@ PermissionPromptBubbleBaseView::PermissionPromptBubbleBaseView( +@@ -197,6 +197,7 @@ PermissionPromptBubbleBaseView::PermissionPromptBubbleBaseView( } SetProperty(views::kElementIdentifierKey, kMainViewId); diff --git a/patches/chrome-browser-ui-views-profiles-profile_menu_view.h.patch b/patches/chrome-browser-ui-views-profiles-profile_menu_view.h.patch index 08b3ac55fc21..36e0b02b2334 100644 --- a/patches/chrome-browser-ui-views-profiles-profile_menu_view.h.patch +++ b/patches/chrome-browser-ui-views-profiles-profile_menu_view.h.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.h b/chrome/browser/ui/views/profiles/profile_menu_view.h -index b4a54bb5c3aae1d16ccf2b07b4c3010ea0edda0e..6ec2ee6090c4b9bffaccfa2e8ef345d8d91127e3 100644 +index b595939f2348e0a02aefc482903749c2556f4d53..8842effba4445b415aa4615053b3b7887300a909 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view.h +++ b/chrome/browser/ui/views/profiles/profile_menu_view.h -@@ -47,6 +47,7 @@ class ProfileMenuView : public ProfileMenuViewBase { +@@ -45,6 +45,7 @@ class ProfileMenuView : public ProfileMenuViewBase { gfx::ImageSkia GetSyncIcon() const override; private: diff --git a/patches/chrome-browser-ui-views-profiles-profile_menu_view_base.h.patch b/patches/chrome-browser-ui-views-profiles-profile_menu_view_base.h.patch index ab7f2edc8c85..d796748c742e 100644 --- a/patches/chrome-browser-ui-views-profiles-profile_menu_view_base.h.patch +++ b/patches/chrome-browser-ui-views-profiles-profile_menu_view_base.h.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.h b/chrome/browser/ui/views/profiles/profile_menu_view_base.h -index c2a9758621f5ea4715a3a302d5e694bcd57aa249..ecbe0d826ca0d7143dc1483add710491416b0836 100644 +index 52a702c9785c4093d784ae21f941c72b243d239b..3b2a22244e545531e9cbc2339d4d8a3531301113 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view_base.h +++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.h -@@ -160,6 +160,7 @@ class ProfileMenuViewBase : public content::WebContentsDelegate, +@@ -163,6 +163,7 @@ class ProfileMenuViewBase : public content::WebContentsDelegate, void set_perform_menu_actions_for_testing(bool perform_menu_actions) { perform_menu_actions_ = perform_menu_actions; } diff --git a/patches/chrome-browser-ui-views-tabs-new_tab_button.h.patch b/patches/chrome-browser-ui-views-tabs-new_tab_button.h.patch index fff30ba4ca21..8d0233d00d63 100644 --- a/patches/chrome-browser-ui-views-tabs-new_tab_button.h.patch +++ b/patches/chrome-browser-ui-views-tabs-new_tab_button.h.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/views/tabs/new_tab_button.h b/chrome/browser/ui/views/tabs/new_tab_button.h -index 924823dfd64f110824127144e9d47ae55c172aa9..866c0eda97c22756ced5e96a80b2fd0b5005295e 100644 +index 2ab48dd2b259b31c6e517854a90a2f883e83965e..45f048d62a0e4aa0ff3ff70e10b0db7857a9d8e5 100644 --- a/chrome/browser/ui/views/tabs/new_tab_button.h +++ b/chrome/browser/ui/views/tabs/new_tab_button.h @@ -50,6 +50,7 @@ class NewTabButton : public views::ImageButton, diff --git a/patches/chrome-browser-ui-views-tabs-tab.cc.patch b/patches/chrome-browser-ui-views-tabs-tab.cc.patch index ea5e209c67c0..324b73605f65 100644 --- a/patches/chrome-browser-ui-views-tabs-tab.cc.patch +++ b/patches/chrome-browser-ui-views-tabs-tab.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc -index 6cfde5828cb0fbe1ea0c39d3bbec1267016b4eb5..f420905f286f5180be1ebcf36aa92b0802584034 100644 +index 4908042cef26dae68dd45a61c6c640e753ed269e..f3957372bb667c9e252d66b4e39fcf295b7c8506 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc -@@ -402,6 +402,7 @@ void Tab::Layout() { +@@ -414,6 +414,7 @@ void Tab::Layout() { int title_right = contents_rect.right(); if (showing_alert_indicator_) { title_right = alert_indicator_button_->x() - after_title_padding; @@ -10,7 +10,7 @@ index 6cfde5828cb0fbe1ea0c39d3bbec1267016b4eb5..f420905f286f5180be1ebcf36aa92b08 } else if (showing_close_button_) { // Allow the title to overlay the close button's empty border padding. title_right = close_x - after_title_padding; -@@ -1021,6 +1022,7 @@ void Tab::UpdateIconVisibility() { +@@ -1033,6 +1034,7 @@ void Tab::UpdateIconVisibility() { available_width -= favicon_width; showing_close_button_ = large_enough_for_close_button; diff --git a/patches/chrome-browser-ui-views-tabs-tab_strip.cc.patch b/patches/chrome-browser-ui-views-tabs-tab_strip.cc.patch index eb730768dea7..808a6c10106f 100644 --- a/patches/chrome-browser-ui-views-tabs-tab_strip.cc.patch +++ b/patches/chrome-browser-ui-views-tabs-tab_strip.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc -index da7ae74dc5f212b6b8b17311751abc6269a71da1..2de5eb3c5656f3998e6b0a481e09b6bbcfb6603d 100644 +index cf9d78aa4593fc26c1ef97a766fc6b5878569b17..078cf784b4f06f600cc0fc9acdc55b563e985c7b 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc @@ -496,6 +496,7 @@ class TabStrip::TabDragContextImpl : public TabDragContext, diff --git a/patches/chrome-browser-ui-views-tabs-tab_style_views.cc.patch b/patches/chrome-browser-ui-views-tabs-tab_style_views.cc.patch index b2cc2933500d..6263272a108a 100644 --- a/patches/chrome-browser-ui-views-tabs-tab_style_views.cc.patch +++ b/patches/chrome-browser-ui-views-tabs-tab_style_views.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc -index 6987eaf6eda6cdafd2dd90de62c6152ebf11ba45..420b583c85c99d38a2648ff535450679ff2ac6a0 100644 +index 3e917d0207c85715805d77dcba8fecdffb53d1a9..4c282b1c5533bc07698fa5bdf75ae682d7bbf601 100644 --- a/chrome/browser/ui/views/tabs/tab_style_views.cc +++ b/chrome/browser/ui/views/tabs/tab_style_views.cc -@@ -135,6 +135,7 @@ class GM2TabStyleViews : public TabStyleViews { +@@ -138,6 +138,7 @@ class GM2TabStyleViews : public TabStyleViews { TabStyle::TabSelectionState GetSelectionState() const; private: @@ -10,7 +10,7 @@ index 6987eaf6eda6cdafd2dd90de62c6152ebf11ba45..420b583c85c99d38a2648ff535450679 // Gets the bounds for the leading and trailing separators for a tab. TabStyle::SeparatorBounds GetSeparatorBounds(float scale) const; -@@ -289,6 +290,7 @@ SkPath GM2TabStyleViews::GetPath(TabStyle::PathType path_type, +@@ -292,6 +293,7 @@ SkPath GM2TabStyleViews::GetPath(TabStyle::PathType path_type, const ShapeModifier shape_modifier = GetShapeModifier(path_type); const bool extend_left_to_bottom = shape_modifier & kNoLowerLeftArc; const bool extend_right_to_bottom = shape_modifier & kNoLowerRightArc; @@ -18,7 +18,7 @@ index 6987eaf6eda6cdafd2dd90de62c6152ebf11ba45..420b583c85c99d38a2648ff535450679 SkPath path; -@@ -606,9 +608,10 @@ TabStyle::SeparatorBounds GM2TabStyleViews::GetSeparatorBounds( +@@ -609,9 +611,10 @@ TabStyle::SeparatorBounds GM2TabStyleViews::GetSeparatorBounds( TabStyle::SeparatorBounds separator_bounds; const int extra_vertical_space = @@ -30,7 +30,7 @@ index 6987eaf6eda6cdafd2dd90de62c6152ebf11ba45..420b583c85c99d38a2648ff535450679 separator_bounds.leading = gfx::RectF( aligned_bounds.x() + corner_radius - separator_margin.right() - -@@ -1023,14 +1026,18 @@ void GM2TabStyleViews::PaintSeparators(gfx::Canvas* canvas) const { +@@ -1028,14 +1031,18 @@ void GM2TabStyleViews::PaintSeparators(gfx::Canvas* canvas) const { SK_AlphaOPAQUE)); }; diff --git a/patches/chrome-browser-ui-views-toolbar-toolbar_view.cc.patch b/patches/chrome-browser-ui-views-toolbar-toolbar_view.cc.patch index 9caa2e01d867..ea1616c91553 100644 --- a/patches/chrome-browser-ui-views-toolbar-toolbar_view.cc.patch +++ b/patches/chrome-browser-ui-views-toolbar-toolbar_view.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc -index 619f741f150975e1a93a32783f9bbfe78e9bee15..a0a09d22c024a5bacd27dfa60ae026ac0c09146b 100644 +index 2ea09fd7e8cc03d17942e843b25f027f4caea3af..c2f16e2273931e7140c30b3d3c1fb68916236229 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc -@@ -461,6 +461,7 @@ void ToolbarView::Init() { +@@ -445,6 +445,7 @@ void ToolbarView::Init() { container_view_->AddChildView(std::move(side_panel_button)); } diff --git a/patches/chrome-browser-ui-webui-BUILD.gn.patch b/patches/chrome-browser-ui-webui-BUILD.gn.patch index 1514e75b891c..56995bca0ea7 100644 --- a/patches/chrome-browser-ui-webui-BUILD.gn.patch +++ b/patches/chrome-browser-ui-webui-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn -index ea52f7f8fb199a97377638ffe02aec67e3f313a7..72fa7a35bc451f8c61b81c5559b4888ad6968b6c 100644 +index c450791517869cd1475cb3732195f72698b4eb99..8ca92d5777988202468d3e68975eed305883724e 100644 --- a/chrome/browser/ui/webui/BUILD.gn +++ b/chrome/browser/ui/webui/BUILD.gn -@@ -70,4 +70,5 @@ source_set("configs") { +@@ -75,4 +75,5 @@ source_set("configs") { deps += [ "//ash/webui/sample_system_web_app_ui" ] } } diff --git a/patches/chrome-browser-ui-webui-chrome_web_ui_controller_factory.cc.patch b/patches/chrome-browser-ui-webui-chrome_web_ui_controller_factory.cc.patch index 33f5c53c3d3b..afd69c51ec9a 100644 --- a/patches/chrome-browser-ui-webui-chrome_web_ui_controller_factory.cc.patch +++ b/patches/chrome-browser-ui-webui-chrome_web_ui_controller_factory.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc -index 75ab7f0bbbeedb05a8b82f9e80e5200a5f89575e..0b4b93522f6007868c14849528c8226a17dde1a2 100644 +index 182cb8d7e8486f401dfad3d672839f45de0698ee..22a9c42cf54587673821a45302897d6d629ffad1 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc -@@ -988,6 +988,7 @@ void ChromeWebUIControllerFactory::GetFaviconForURL( +@@ -981,6 +981,7 @@ void ChromeWebUIControllerFactory::GetFaviconForURL( // static ChromeWebUIControllerFactory* ChromeWebUIControllerFactory::GetInstance() { diff --git a/patches/chrome-browser-ui-webui-downloads-downloads_ui.cc.patch b/patches/chrome-browser-ui-webui-downloads-downloads_ui.cc.patch index 21b5c6e3cdcb..5a97f5ccfa07 100644 --- a/patches/chrome-browser-ui-webui-downloads-downloads_ui.cc.patch +++ b/patches/chrome-browser-ui-webui-downloads-downloads_ui.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/webui/downloads/downloads_ui.cc b/chrome/browser/ui/webui/downloads/downloads_ui.cc -index aa26b88ebba2e3765623675519d71335ded67660..e0573ca48104112bbab625ae9e412816a7993bbb 100644 +index e56ad5469d6cded25cf3b37466973d6162cb4a50..8a49018ce3218ca3aba1a4abb5595fc9874c6512 100644 --- a/chrome/browser/ui/webui/downloads/downloads_ui.cc +++ b/chrome/browser/ui/webui/downloads/downloads_ui.cc @@ -60,6 +60,7 @@ namespace { diff --git a/patches/chrome-browser-ui-webui-extensions-extensions_ui.cc.patch b/patches/chrome-browser-ui-webui-extensions-extensions_ui.cc.patch index dde3a2199d28..2e0b15f3ff40 100644 --- a/patches/chrome-browser-ui-webui-extensions-extensions_ui.cc.patch +++ b/patches/chrome-browser-ui-webui-extensions-extensions_ui.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc -index 625352ca9ae74c09ecab797571b2075727717757..d4111c2a45895914675252b3c1c05b52a42b7062 100644 +index cf6352455a01a1f6ac234eb58ee4c8d1333783f9..bc27e29f2cec81e20bba658801b6defc24974870 100644 --- a/chrome/browser/ui/webui/extensions/extensions_ui.cc +++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc -@@ -433,6 +433,7 @@ content::WebUIDataSource* CreateAndAddExtensionsSource(Profile* profile, +@@ -440,6 +440,7 @@ content::WebUIDataSource* CreateAndAddExtensionsSource(Profile* profile, "safetyCheckShowReviewPanel", base::FeatureList::IsEnabled(features::kSafetyCheckExtensions)); diff --git a/patches/chrome-browser-ui-webui-settings-people_handler.cc.patch b/patches/chrome-browser-ui-webui-settings-people_handler.cc.patch index c8da616fdd2d..e3bb4bde3b1e 100644 --- a/patches/chrome-browser-ui-webui-settings-people_handler.cc.patch +++ b/patches/chrome-browser-ui-webui-settings-people_handler.cc.patch @@ -1,5 +1,5 @@ diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc -index 32cc442c8bf1e6cf1e86b156697231839799898b..a5946468ff148195e81e33c4200acd9106360b85 100644 +index a134e692f136fd468a9650b0ca08f9ce0ec658b2..1904f0358a403683dca8f30a3c73f6a9570df6f7 100644 --- a/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chrome/browser/ui/webui/settings/people_handler.cc @@ -875,6 +875,7 @@ void PeopleHandler::OnStateChanged(syncer::SyncService* sync_service) { diff --git a/patches/chrome-browser-ui-webui-settings-settings_localized_strings_provider.cc.patch b/patches/chrome-browser-ui-webui-settings-settings_localized_strings_provider.cc.patch index 1034f7e5c96b..a7e0b3ce1cf3 100644 --- a/patches/chrome-browser-ui-webui-settings-settings_localized_strings_provider.cc.patch +++ b/patches/chrome-browser-ui-webui-settings-settings_localized_strings_provider.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc -index 2c54740738d1fbaf977eb150e91428596ff9ed94..aea9364a758b4efa90e14c8a2f4a6ea886d9d511 100644 +index 899ae48f57d2c1bc83aba77d70802f8c4a577c87..0fe36a25eaa6125c6c5bb3b8060140b99bad4057 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc -@@ -3710,6 +3710,7 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, +@@ -3533,6 +3533,7 @@ void AddLocalizedStrings(content::WebUIDataSource* html_source, policy_indicator::AddLocalizedStrings(html_source); AddSecurityKeysStrings(html_source); diff --git a/patches/chrome-browser-ui-webui-settings-site_settings_helper.cc.patch b/patches/chrome-browser-ui-webui-settings-site_settings_helper.cc.patch index 9527a53ac2b1..30d6429641ce 100644 --- a/patches/chrome-browser-ui-webui-settings-site_settings_helper.cc.patch +++ b/patches/chrome-browser-ui-webui-settings-site_settings_helper.cc.patch @@ -1,16 +1,16 @@ diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc -index 0fa6df3882ca180c0ecfa89f8294b48f1adde711..57c4a4541449cc261607fadfaa9f7494a7b2da0c 100644 +index 9bc1f5089a76bb2a6ce0559c9074ca0995bc64f1..478e1c6194fb994f206191d375493b164d5334a0 100644 --- a/chrome/browser/ui/webui/settings/site_settings_helper.cc +++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc -@@ -199,6 +199,7 @@ const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { - {ContentSettingsType::ALL_SCREEN_CAPTURE, nullptr}, +@@ -198,6 +198,7 @@ const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { {ContentSettingsType::COOKIE_CONTROLS_METADATA, nullptr}, {ContentSettingsType::TPCD_SUPPORT, nullptr}, + {ContentSettingsType::TPCD_METADATA_GRANTS, nullptr}, + BRAVE_CONTENT_SETTINGS_TYPE_GROUP_NAMES_LIST }; static_assert(std::size(kContentSettingsTypeGroupNames) == -@@ -491,6 +492,7 @@ bool HasRegisteredGroupName(ContentSettingsType type) { +@@ -461,6 +462,7 @@ bool HasRegisteredGroupName(ContentSettingsType type) { } ContentSettingsType ContentSettingsTypeFromGroupName(base::StringPiece name) { diff --git a/patches/chrome-browser-web_applications-os_integration-web_app_shortcut_mac.mm.patch b/patches/chrome-browser-web_applications-os_integration-web_app_shortcut_mac.mm.patch index 57b7e88936f7..119e135e25ae 100644 --- a/patches/chrome-browser-web_applications-os_integration-web_app_shortcut_mac.mm.patch +++ b/patches/chrome-browser-web_applications-os_integration-web_app_shortcut_mac.mm.patch @@ -1,8 +1,8 @@ diff --git a/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm b/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm -index 68964b425cec5cdc07f22d07c8bd2bf04bf64d53..79aa75fadaecc58424d95e67134bae3d123eecc4 100644 +index b7d0c1e788d05aa9794b0016863ffcbdfdd3cc68..0a831aa769b07236e5eb83460741cb52bc944615 100644 --- a/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm +++ b/chrome/browser/web_applications/os_integration/web_app_shortcut_mac.mm -@@ -1171,6 +1171,7 @@ base::FilePath GetChromeAppsFolder() { +@@ -1135,6 +1135,7 @@ base::FilePath GetChromeAppsFolder() { if (path.empty()) return path; diff --git a/patches/chrome-chrome_repack_locales.gni.patch b/patches/chrome-chrome_repack_locales.gni.patch index 23f9e9a6b1bc..96b934fde644 100644 --- a/patches/chrome-chrome_repack_locales.gni.patch +++ b/patches/chrome-chrome_repack_locales.gni.patch @@ -1,5 +1,5 @@ diff --git a/chrome/chrome_repack_locales.gni b/chrome/chrome_repack_locales.gni -index adc881122cb9c191c1f43cfa72cff69281775b70..a233866b274c43bae71f8deddb359fec967d1bdd 100644 +index 7aa8989a0f47167440824f0531ee9956d2f24098..d7a9da068994a9450eca2655dd5c038be0c3f55f 100644 --- a/chrome/chrome_repack_locales.gni +++ b/chrome/chrome_repack_locales.gni @@ -40,6 +40,7 @@ template("chrome_repack_locales") { @@ -10,7 +10,7 @@ index adc881122cb9c191c1f43cfa72cff69281775b70..a233866b274c43bae71f8deddb359fec if (!defined(deps)) { deps = [] } -@@ -60,6 +61,7 @@ template("chrome_repack_locales") { +@@ -62,6 +63,7 @@ template("chrome_repack_locales") { "//ui/strings:ax_strings", "//ui/strings:ui_strings", ] @@ -18,3 +18,14 @@ index adc881122cb9c191c1f43cfa72cff69281775b70..a233866b274c43bae71f8deddb359fec if (defined(invoker.deps)) { deps += invoker.deps } +@@ -106,8 +108,8 @@ template("chrome_repack_locales") { + ] + } else { + source_patterns += [ +- "${root_gen_dir}/chrome/chromium_strings_", +- "${root_gen_dir}/components/strings/components_chromium_strings_", ++ "${root_gen_dir}/chrome/${branding_path_product}_strings_", ++ "${root_gen_dir}/components/strings/components_${branding_path_product}_strings_", + ] + } + diff --git a/patches/chrome-common-BUILD.gn.patch b/patches/chrome-common-BUILD.gn.patch index 877381db5e52..db0d5fcaa30c 100644 --- a/patches/chrome-common-BUILD.gn.patch +++ b/patches/chrome-common-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn -index c3ec18003787c0ea08eb6ecf741e485ef7ffbfb3..a4802416b037dc445427e7753ac704f4c0f33401 100644 +index e75d7bc0b01870f71f7a698c9620c24e66f8897c..4e7354c60e1d4948a564fdb62eb6402c141d3c4c 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn @@ -97,6 +97,7 @@ source_set("channel_info") { @@ -18,7 +18,7 @@ index c3ec18003787c0ea08eb6ecf741e485ef7ffbfb3..a4802416b037dc445427e7753ac704f4 if (enable_extensions) { sources += [ -@@ -540,6 +542,7 @@ static_library("non_code_constants") { +@@ -539,6 +541,7 @@ static_library("non_code_constants") { "//printing/buildflags", "//ui/base:buildflags", ] diff --git a/patches/chrome-common-extensions-api-developer_private.idl.patch b/patches/chrome-common-extensions-api-developer_private.idl.patch index 80699bbf0f40..215e6ec59264 100644 --- a/patches/chrome-common-extensions-api-developer_private.idl.patch +++ b/patches/chrome-common-extensions-api-developer_private.idl.patch @@ -1,8 +1,8 @@ diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl -index b733a36ef4a8ff7d8a82415fc78e2079351bf885..d57ebbfe4cf01050b0e1eaec576416f07dc0a960 100644 +index 86e86c00715c8706bf94063a1a8066a8ba5e5b7c..39b74a535159630e05a2eced7df53b744e08c378 100644 --- a/chrome/common/extensions/api/developer_private.idl +++ b/chrome/common/extensions/api/developer_private.idl -@@ -241,6 +241,7 @@ namespace developerPrivate { +@@ -245,6 +245,7 @@ namespace developerPrivate { DOMString iconUrl; DOMString id; AccessModifier incognitoAccess; diff --git a/patches/chrome-installer-mini_installer-BUILD.gn.patch b/patches/chrome-installer-mini_installer-BUILD.gn.patch index dc795f8d0947..3146364bfb0d 100644 --- a/patches/chrome-installer-mini_installer-BUILD.gn.patch +++ b/patches/chrome-installer-mini_installer-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/installer/mini_installer/BUILD.gn b/chrome/installer/mini_installer/BUILD.gn -index e9b34c78999b00440378010a8e35e6e8a502ca77..9f0b6de11c0481cf7a8583ebbd7b28d7935eb5d1 100644 +index 71803adcfbe02b8c76b58ddb6f657008c2d2ba88..41f0144d5669bc33ba9c6d0e53eceb8a73642ca8 100644 --- a/chrome/installer/mini_installer/BUILD.gn +++ b/chrome/installer/mini_installer/BUILD.gn -@@ -117,7 +117,7 @@ group("setup_runtime_deps") { +@@ -115,7 +115,7 @@ group("setup_runtime_deps") { packed_files_rc_file = "$target_gen_dir/mini_installer/packed_files.rc" @@ -11,7 +11,7 @@ index e9b34c78999b00440378010a8e35e6e8a502ca77..9f0b6de11c0481cf7a8583ebbd7b28d7 script = "//chrome/tools/build/win/create_installer_archive.py" release_file = "chrome.release" -@@ -227,7 +227,7 @@ action("mini_installer_archive") { +@@ -229,7 +229,7 @@ action("mini_installer_archive") { ] } @@ -20,7 +20,7 @@ index e9b34c78999b00440378010a8e35e6e8a502ca77..9f0b6de11c0481cf7a8583ebbd7b28d7 sources = [ "mini_installer_exe_main.cc", packed_files_rc_file, -@@ -284,7 +284,7 @@ executable("mini_installer") { +@@ -286,7 +286,7 @@ executable("mini_installer") { no_default_deps = true ldflags += [ "/ENTRY:MainEntryPoint" ] } diff --git a/patches/chrome-installer-mini_installer-chrome.release.patch b/patches/chrome-installer-mini_installer-chrome.release.patch index 96a50d802700..4c9e58234d03 100644 --- a/patches/chrome-installer-mini_installer-chrome.release.patch +++ b/patches/chrome-installer-mini_installer-chrome.release.patch @@ -1,5 +1,5 @@ diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release -index 088d1778f317c4df323f741622583b463baf5bdf..47ed2e382bfde4bb69eb7b9642851a3f4e9b3612 100644 +index 1bbc88ff7dd3545b94d8d5f3dd0ed60cd8c1f093..757657fb76edcf074780436e5617f4a60db4c879 100644 --- a/chrome/installer/mini_installer/chrome.release +++ b/chrome/installer/mini_installer/chrome.release @@ -6,7 +6,7 @@ diff --git a/patches/chrome-installer-setup-BUILD.gn.patch b/patches/chrome-installer-setup-BUILD.gn.patch index 36d0615e373e..d251c8cd360e 100644 --- a/patches/chrome-installer-setup-BUILD.gn.patch +++ b/patches/chrome-installer-setup-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/chrome/installer/setup/BUILD.gn b/chrome/installer/setup/BUILD.gn -index 3bd87929bc917325fe6ae3906b897cb4d29089c8..1bf36519d7f08069f49dcd4ab814e84134337cf8 100644 +index 7960bc042c5ebf556f689ca7a14fb98c1b7bb33a..e81fada077467b34369a72d81e8306c2d47b2bb1 100644 --- a/chrome/installer/setup/BUILD.gn +++ b/chrome/installer/setup/BUILD.gn @@ -130,6 +130,7 @@ if (is_win) { diff --git a/patches/chrome-installer-util-BUILD.gn.patch b/patches/chrome-installer-util-BUILD.gn.patch index cfff639f88d8..976f16107b50 100644 --- a/patches/chrome-installer-util-BUILD.gn.patch +++ b/patches/chrome-installer-util-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/installer/util/BUILD.gn b/chrome/installer/util/BUILD.gn -index 17c55843a77791f766319e4f352bc3d43d57ccc6..4009e16bd5f7286dae34b45b7a793e00e2c4f85e 100644 +index eec8f3b69d89ac3f302e447951c9d9f2a492e030..02982455db04926f910658475f1ea12df2f122ad 100644 --- a/chrome/installer/util/BUILD.gn +++ b/chrome/installer/util/BUILD.gn -@@ -204,6 +204,7 @@ static_library("with_no_strings") { +@@ -205,6 +205,7 @@ static_library("with_no_strings") { "initial_preferences.h", ] } @@ -10,11 +10,11 @@ index 17c55843a77791f766319e4f352bc3d43d57ccc6..4009e16bd5f7286dae34b45b7a793e00 } # Use this version of installer_util to link to the generated strings in .rc -@@ -240,6 +241,7 @@ generate_embedded_i18n("generate_strings") { +@@ -241,6 +242,7 @@ generate_embedded_i18n("generate_strings") { output_file_name_base = "installer_util_strings" branding = branding_path_product -+ sources = [ "//chrome/app/brave_strings.grd" ] ++ sources = [ "//chrome/app/brave_strings.grd" ] import("//brave/installer/util/sources.gni") extractor_datafile = brave_installer_util_generate_strings_extractor_datafile } # Compile the generated .rc file. diff --git a/patches/chrome-installer-util-google_update_settings.cc.patch b/patches/chrome-installer-util-google_update_settings.cc.patch index 4debf02fdef1..b6125b8531ef 100644 --- a/patches/chrome-installer-util-google_update_settings.cc.patch +++ b/patches/chrome-installer-util-google_update_settings.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc -index 8aa98ee44068cebe8c27f2bf7c6b3cf67a23b81e..299673a00a76304a33c59b943e0b26b154d94a6e 100644 +index 6e06ab8f05a17e167f7f5cfd7882fb50afb5e9fb..9647dbc388b7de27814e0684b1ea6c46217b1d00 100644 --- a/chrome/installer/util/google_update_settings.cc +++ b/chrome/installer/util/google_update_settings.cc -@@ -30,7 +30,11 @@ using base::win::RegKey; +@@ -32,7 +32,11 @@ using base::win::RegKey; using installer::InstallationState; const wchar_t GoogleUpdateSettings::kPoliciesKey[] = @@ -14,7 +14,7 @@ index 8aa98ee44068cebe8c27f2bf7c6b3cf67a23b81e..299673a00a76304a33c59b943e0b26b1 const wchar_t GoogleUpdateSettings::kUpdatePolicyValue[] = L"UpdateDefault"; const wchar_t GoogleUpdateSettings::kDownloadPreferencePolicyValue[] = L"DownloadPreference"; -@@ -42,6 +46,10 @@ const wchar_t GoogleUpdateSettings::kCheckPeriodOverrideMinutes[] = +@@ -44,6 +48,10 @@ const wchar_t GoogleUpdateSettings::kCheckPeriodOverrideMinutes[] = const int GoogleUpdateSettings::kCheckPeriodOverrideMinutesMax = 60 * 24 * 7 * 6; diff --git a/patches/chrome-installer-util-prebuild-create_installer_string_rc.py.patch b/patches/chrome-installer-util-prebuild-create_installer_string_rc.py.patch deleted file mode 100644 index b0ecd6da0f77..000000000000 --- a/patches/chrome-installer-util-prebuild-create_installer_string_rc.py.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/chrome/installer/util/prebuild/create_installer_string_rc.py b/chrome/installer/util/prebuild/create_installer_string_rc.py -index 9b174616ccee685ce6e672084795a25b8f067426..509876a90b75a18cb9155abecbc5990940725488 100755 ---- a/chrome/installer/util/prebuild/create_installer_string_rc.py -+++ b/chrome/installer/util/prebuild/create_installer_string_rc.py -@@ -104,3 +104,5 @@ MODE_SPECIFIC_STRINGS = { - ], - }, - } -+ -+from chrome.installer.util.prebuild.create_installer_string_rc import MODE_SPECIFIC_STRINGS diff --git a/patches/chrome-renderer-BUILD.gn.patch b/patches/chrome-renderer-BUILD.gn.patch index da1e270ef2c4..384e6ab8202d 100644 --- a/patches/chrome-renderer-BUILD.gn.patch +++ b/patches/chrome-renderer-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn -index 5bf67204d500609ba0d431ac7e28c1c569f46790..82fff891b240fe493f8c4ed41129bc672faf1203 100644 +index 01c93bf7e64afc49c38a5a13c6f558efe1e3e5d9..1624b54d91ff51bbc6515ee7129f8bbeedcab48c 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn @@ -233,6 +233,7 @@ static_library("renderer") { diff --git a/patches/chrome-renderer-chrome_content_renderer_client.cc.patch b/patches/chrome-renderer-chrome_content_renderer_client.cc.patch index 4fa1693afa7f..c309c7227571 100644 --- a/patches/chrome-renderer-chrome_content_renderer_client.cc.patch +++ b/patches/chrome-renderer-chrome_content_renderer_client.cc.patch @@ -1,8 +1,8 @@ diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc -index 8d02ca21674b13dd2ae11cb79b8d85dfcc4cb217..d1b90c854d669475aa0640b745612f07d1fa4aa7 100644 +index c573a3908fd43f678af1ca5142c5f4258ff426bf..1aac3e7b57b4d213dc1d7ff21392b55671acba86 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc -@@ -584,7 +584,7 @@ void ChromeContentRendererClient::RenderFrameCreated( +@@ -588,7 +588,7 @@ void ChromeContentRendererClient::RenderFrameCreated( ChromeExtensionsRendererClient::GetInstance()->extension_dispatcher()); #endif content_settings::ContentSettingsAgentImpl* content_settings = @@ -11,9 +11,9 @@ index 8d02ca21674b13dd2ae11cb79b8d85dfcc4cb217..d1b90c854d669475aa0640b745612f07 render_frame, should_allow_for_content_settings, std::move(content_settings_delegate)); if (chrome_observer_.get()) { -@@ -756,6 +756,7 @@ void ChromeContentRendererClient::RenderFrameCreated( - render_frame)); - } +@@ -764,6 +764,7 @@ void ChromeContentRendererClient::RenderFrameCreated( + #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS) + MultilineDetector::InstallIfNecessary(render_frame); #endif + BRAVE_RENDER_FRAME_CREATED } diff --git a/patches/chrome-test-BUILD.gn.patch b/patches/chrome-test-BUILD.gn.patch index 7e9260b1fe0b..7e493ff038fd 100644 --- a/patches/chrome-test-BUILD.gn.patch +++ b/patches/chrome-test-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn -index 42d1deb5d901e84acb56dadcb7d6d5a4b7c06989..326f76810c7c620562e2729ec3c4a71ffe2ab51f 100644 +index 8f9b476a538dd5a0e91edc725eed4463b4a92e05..8aa1cc9c68c2feaf22cb1e25f2eaefb1ba68ebb9 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn -@@ -428,6 +428,7 @@ static_library("test_support") { +@@ -433,6 +433,7 @@ static_library("test_support") { "//ui/gl", ] diff --git a/patches/chrome-test-data-webui-settings-BUILD.gn.patch b/patches/chrome-test-data-webui-settings-BUILD.gn.patch index e8a36e90eb53..4c664cdc3451 100644 --- a/patches/chrome-test-data-webui-settings-BUILD.gn.patch +++ b/patches/chrome-test-data-webui-settings-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn -index 97f10c465bba72b320183814e360a004473fb5a6..b6e75653b4ca0762597ebb0d1c3ed9da8f15bc78 100644 +index 3c6f511fc32a16e475334e7cba8077ec10ab1b40..0612bcd9be59910e8175ed34cbed785775e92780 100644 --- a/chrome/test/data/webui/settings/BUILD.gn +++ b/chrome/test/data/webui/settings/BUILD.gn -@@ -226,6 +226,7 @@ build_webui_tests("build") { +@@ -225,6 +225,7 @@ build_webui_tests("build") { ts_definitions += [ "//tools/typescript/definitions/quick_unlock_private.d.ts" ] } diff --git a/patches/chrome-tools-build-win-create_installer_archive.py.patch b/patches/chrome-tools-build-win-create_installer_archive.py.patch index 490faaa5252f..6cecb871311e 100644 --- a/patches/chrome-tools-build-win-create_installer_archive.py.patch +++ b/patches/chrome-tools-build-win-create_installer_archive.py.patch @@ -1,8 +1,8 @@ diff --git a/chrome/tools/build/win/create_installer_archive.py b/chrome/tools/build/win/create_installer_archive.py -index ba75899c40db87a3ddb138912855cb6e1bbca45d..33593d635c90f167d830f6258d2dada56874cd0d 100755 +index 07387a69ada91e01b08043dfdc2029228890f937..dafa83866f9d4305ec2fa5173a5007c73bbe7cc4 100755 --- a/chrome/tools/build/win/create_installer_archive.py +++ b/chrome/tools/build/win/create_installer_archive.py -@@ -638,6 +638,7 @@ def _ParseOptions(): +@@ -645,6 +645,7 @@ def _ParseOptions(): 'with the installer archive {x86|x64}.') parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False) @@ -10,7 +10,7 @@ index ba75899c40db87a3ddb138912855cb6e1bbca45d..33593d635c90f167d830f6258d2dada5 options, _ = parser.parse_args() if not options.build_dir: -@@ -666,6 +667,7 @@ def _ParseOptions(): +@@ -673,6 +674,7 @@ def _ParseOptions(): return options diff --git a/patches/components-BUILD.gn.patch b/patches/components-BUILD.gn.patch new file mode 100644 index 000000000000..8c45f7ad1624 --- /dev/null +++ b/patches/components-BUILD.gn.patch @@ -0,0 +1,13 @@ +diff --git a/components/BUILD.gn b/components/BUILD.gn +index 0f65455cfdc6f8d409b951eb9deb517a0cffe862..79d73a48dc2bf9d1be6b20f0afd6af7e9eba38df 100644 +--- a/components/BUILD.gn ++++ b/components/BUILD.gn +@@ -774,7 +774,7 @@ repack("components_tests_pak") { + if (is_chrome_branded) { + sources += [ "${root_gen_dir}/components/strings/components_google_chrome_strings_en-US.pak" ] + } else { +- sources += [ "${root_gen_dir}/components/strings/components_chromium_strings_en-US.pak" ] ++ sources += [ "${root_gen_dir}/components/strings/components_${branding_path_product}_strings_en-US.pak" ] + } + } + diff --git a/patches/components-bookmarks-browser-bookmark_model.h.patch b/patches/components-bookmarks-browser-bookmark_model.h.patch index 9c2c4af85bc1..bc5e602fdaa9 100644 --- a/patches/components-bookmarks-browser-bookmark_model.h.patch +++ b/patches/components-bookmarks-browser-bookmark_model.h.patch @@ -1,5 +1,5 @@ diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h -index 815a6cf5f7c4f69618747ab6f5726d3e91995aca..baf5eb9f889ad021d79adce8eb01a309d5b46265 100644 +index 6e19fab5ed3efaa0767d657afa750c5e6c55f114..7c18cbf2b45374066d6338e634a42ddc02cd31e5 100644 --- a/components/bookmarks/browser/bookmark_model.h +++ b/components/bookmarks/browser/bookmark_model.h @@ -385,6 +385,7 @@ class BookmarkModel final : public BookmarkUndoProvider, diff --git a/patches/components-component_updater-component_updater_service.h.patch b/patches/components-component_updater-component_updater_service.h.patch index 2a9b96bf4585..722a1a953a68 100644 --- a/patches/components-component_updater-component_updater_service.h.patch +++ b/patches/components-component_updater-component_updater_service.h.patch @@ -1,16 +1,16 @@ diff --git a/components/component_updater/component_updater_service.h b/components/component_updater/component_updater_service.h -index 36215051767a1b1ff4d924e977b438047ccc1527..7f5666a756344fdd27baae84a0c4d323b9be9c12 100644 +index 1b718ecf09f706f5d56f912c0b4aa34555b6a3ac..07c66a6d005d9ed99bfc7d46f364630d31391c0b 100644 --- a/components/component_updater/component_updater_service.h +++ b/components/component_updater/component_updater_service.h -@@ -186,6 +186,7 @@ class ComponentUpdateService { - +@@ -191,6 +191,7 @@ class ComponentUpdateService { + friend class screen_ai::ScreenAIDownloaderNonChromeOS; friend class speech::SodaInstallerImpl; friend class ::ComponentsHandler; + BRAVE_COMPONENT_UPDATER_SERVICE_H_ FRIEND_TEST_ALL_PREFIXES(ComponentInstallerTest, RegisterComponent); }; -@@ -199,6 +200,7 @@ class OnDemandUpdater { +@@ -204,6 +205,7 @@ class OnDemandUpdater { enum class Priority { BACKGROUND = 0, FOREGROUND = 1 }; virtual ~OnDemandUpdater() = default; diff --git a/patches/components-content_settings-browser-page_specific_content_settings.cc.patch b/patches/components-content_settings-browser-page_specific_content_settings.cc.patch index 409b26bb5be3..8037ca1361ee 100644 --- a/patches/components-content_settings-browser-page_specific_content_settings.cc.patch +++ b/patches/components-content_settings-browser-page_specific_content_settings.cc.patch @@ -1,8 +1,8 @@ diff --git a/components/content_settings/browser/page_specific_content_settings.cc b/components/content_settings/browser/page_specific_content_settings.cc -index 935d5f592d2aac08818020c8cd234e76e44f1545..9248e1ccf2630734985719a0e8d69bbcd07d5b93 100644 +index 1866be61c5e5a4db4c31cafc5cc971795033e8ce..c6ad43e2beac9721a4eb8273fcbdee6c98d3a48c 100644 --- a/components/content_settings/browser/page_specific_content_settings.cc +++ b/components/content_settings/browser/page_specific_content_settings.cc -@@ -771,6 +771,7 @@ bool PageSpecificContentSettings::IsContentBlocked( +@@ -796,6 +796,7 @@ bool PageSpecificContentSettings::IsContentBlocked( content_type == ContentSettingsType::ADS || content_type == ContentSettingsType::SOUND || content_type == ContentSettingsType::CLIPBOARD_READ_WRITE || @@ -10,7 +10,7 @@ index 935d5f592d2aac08818020c8cd234e76e44f1545..9248e1ccf2630734985719a0e8d69bbc content_type == ContentSettingsType::SENSORS || content_type == ContentSettingsType::GEOLOCATION) { const auto& it = content_settings_status_.find(content_type); -@@ -796,6 +797,7 @@ bool PageSpecificContentSettings::IsContentAllowed( +@@ -821,6 +822,7 @@ bool PageSpecificContentSettings::IsContentAllowed( content_type != ContentSettingsType::MEDIASTREAM_CAMERA && content_type != ContentSettingsType::MIDI_SYSEX && content_type != ContentSettingsType::CLIPBOARD_READ_WRITE && diff --git a/patches/components-content_settings-core-browser-BUILD.gn.patch b/patches/components-content_settings-core-browser-BUILD.gn.patch index 4bf331f3ca62..08a1c0256378 100644 --- a/patches/components-content_settings-core-browser-BUILD.gn.patch +++ b/patches/components-content_settings-core-browser-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/components/content_settings/core/browser/BUILD.gn b/components/content_settings/core/browser/BUILD.gn -index 03c3d6a249733817074f8663b9eeb31e797a7282..e5e668aee61d877d1f3822ed521ece908e95e102 100644 +index e774418d741d9cf856a8581de6685cbfea8dd2d4..50c3e24d658c3347f50002a695bd06a7004fee84 100644 --- a/components/content_settings/core/browser/BUILD.gn +++ b/components/content_settings/core/browser/BUILD.gn @@ -85,6 +85,7 @@ static_library("browser") { diff --git a/patches/components-content_settings-core-browser-content_settings_pref.cc.patch b/patches/components-content_settings-core-browser-content_settings_pref.cc.patch index 4dbd901eb4ff..27d7f83fadc7 100644 --- a/patches/components-content_settings-core-browser-content_settings_pref.cc.patch +++ b/patches/components-content_settings-core-browser-content_settings_pref.cc.patch @@ -1,5 +1,5 @@ diff --git a/components/content_settings/core/browser/content_settings_pref.cc b/components/content_settings/core/browser/content_settings_pref.cc -index 4e7b1a90b41149f13ebed02ce6b75824aeab4045..79a3e81f595b4a2b9a41d0a3edc00684cd350dad 100644 +index 8d03378567a0f9bb3fe2e0c2c671565917f63064..61ec5307e30aebb89c5f3a4263e3f76698895777 100644 --- a/components/content_settings/core/browser/content_settings_pref.cc +++ b/components/content_settings/core/browser/content_settings_pref.cc @@ -200,6 +200,7 @@ void ContentSettingsPref::SetWebsiteSetting( diff --git a/patches/components-content_settings-core-browser-content_settings_registry.cc.patch b/patches/components-content_settings-core-browser-content_settings_registry.cc.patch index 38f4b0f04fad..f25a7c3926a9 100644 --- a/patches/components-content_settings-core-browser-content_settings_registry.cc.patch +++ b/patches/components-content_settings-core-browser-content_settings_registry.cc.patch @@ -1,11 +1,11 @@ diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc -index fe872eb3a92a26e93b40150d0d76e1b6bbb734f3..a209e0df989046137778821cdf115c1ff8be37ac 100644 +index 0486610875890ed1e35fb506459e21b214633a07..f8ea53db63b958f8b97a8d5fc5d8f16fe9782714 100644 --- a/components/content_settings/core/browser/content_settings_registry.cc +++ b/components/content_settings/core/browser/content_settings_registry.cc -@@ -609,6 +609,7 @@ void ContentSettingsRegistry::Init() { - WebsiteSettingsRegistry::ALL_PLATFORMS, - ContentSettingsInfo::INHERIT_IN_INCOGNITO, - ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS); +@@ -629,6 +629,7 @@ void ContentSettingsRegistry::Init() { + WebsiteSettingsRegistry::DESKTOP, + ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE, + ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY); + BRAVE_INIT } diff --git a/patches/components-content_settings-core-browser-content_settings_uma_util.cc.patch b/patches/components-content_settings-core-browser-content_settings_uma_util.cc.patch index ff36b2d7d89e..b0aecc09c98a 100644 --- a/patches/components-content_settings-core-browser-content_settings_uma_util.cc.patch +++ b/patches/components-content_settings-core-browser-content_settings_uma_util.cc.patch @@ -1,8 +1,8 @@ diff --git a/components/content_settings/core/browser/content_settings_uma_util.cc b/components/content_settings/core/browser/content_settings_uma_util.cc -index 6516306b9d9adf454a78542d22301ba54296c1db..775cd641d837806490acf9e2917759a068273016 100644 +index bee86e7d29d36d24496b23a3dcda54a7ed2d6aa5..f1daf3c9cb657456c32300e25292976b9a1a3308 100644 --- a/components/content_settings/core/browser/content_settings_uma_util.cc +++ b/components/content_settings/core/browser/content_settings_uma_util.cc -@@ -120,6 +120,7 @@ constexpr auto kHistogramValue = base::MakeFixedFlatMap default_match_to_preserve) { result_.SortAndCull(input_, template_url_service_, triggered_feature_service_, default_match_to_preserve); diff --git a/patches/components-omnibox-browser-omnibox_edit_model.cc.patch b/patches/components-omnibox-browser-omnibox_edit_model.cc.patch index 4f8481f5fac7..fdae2297c866 100644 --- a/patches/components-omnibox-browser-omnibox_edit_model.cc.patch +++ b/patches/components-omnibox-browser-omnibox_edit_model.cc.patch @@ -1,5 +1,5 @@ diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc -index 52a4ae976393b99ee36f9382e4b870ef57c0bed3..138f335c70f01a264b84a67dbd9ce2b92fabcbdf 100644 +index 24eeaac09aaa36a4931fa97808a136bec284f27f..d2ac9780799c3f84638ea925d0e6d0e8659cb7db 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc @@ -526,6 +526,7 @@ void OmniboxEditModel::AdjustTextForCopy(int sel_min, diff --git a/patches/components-os_crypt-sync-keychain_password_mac.mm.patch b/patches/components-os_crypt-sync-keychain_password_mac.mm.patch index 6cc88f39a2bf..38fc799fcead 100644 --- a/patches/components-os_crypt-sync-keychain_password_mac.mm.patch +++ b/patches/components-os_crypt-sync-keychain_password_mac.mm.patch @@ -1,5 +1,5 @@ diff --git a/components/os_crypt/sync/keychain_password_mac.mm b/components/os_crypt/sync/keychain_password_mac.mm -index f6269925af68ce3ef9fb684bf4a1662874becae9..241910b44514e5121bc6cf7107e3d469675ff0ce 100644 +index a6b736f8be0fb24bd61f291ca60c1a9ccae30db7..ecefb1bc3b24d3e0599002c02cb829652f53ae79 100644 --- a/components/os_crypt/sync/keychain_password_mac.mm +++ b/components/os_crypt/sync/keychain_password_mac.mm @@ -64,12 +64,14 @@ std::string AddRandomPasswordToKeychain(const AppleKeychain& keychain, diff --git a/patches/components-page_info-BUILD.gn.patch b/patches/components-page_info-BUILD.gn.patch index 614965dfec37..c38415514ca8 100644 --- a/patches/components-page_info-BUILD.gn.patch +++ b/patches/components-page_info-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/components/page_info/BUILD.gn b/components/page_info/BUILD.gn -index 7178afd20e20ff1dabdc12e0f8ae1a971e4334d4..f146bdfee73f120d990e03fab769747fbd6d61f8 100644 +index b9c9b5f8d8ec256b1064a93414ec819b01cd2e25..da6b20696ad46e2aa693b3c9fc1eef7500048e9b 100644 --- a/components/page_info/BUILD.gn +++ b/components/page_info/BUILD.gn -@@ -46,6 +46,7 @@ static_library("page_info") { +@@ -47,6 +47,7 @@ static_library("page_info") { "//services/device/public/cpp:device_features", "//services/metrics/public/cpp:ukm_builders", ] diff --git a/patches/components-page_info-page_info.cc.patch b/patches/components-page_info-page_info.cc.patch index 5c0468e5329f..3773cd037d49 100644 --- a/patches/components-page_info-page_info.cc.patch +++ b/patches/components-page_info-page_info.cc.patch @@ -1,8 +1,8 @@ diff --git a/components/page_info/page_info.cc b/components/page_info/page_info.cc -index 18dd31f524a094def51ec750d5258b228c51a272..067a1176474a980acb2583614581b024372a74db 100644 +index ee84486bd7d1cd054565e4455e0b59a09b9c283f..2ec26cf37ddc4ab601498366f250b49a95910bf8 100644 --- a/components/page_info/page_info.cc +++ b/components/page_info/page_info.cc -@@ -1230,6 +1230,7 @@ void PageInfo::PopulatePermissionInfo(PermissionInfo& permission_info, +@@ -1237,6 +1237,7 @@ void PageInfo::PopulatePermissionInfo(PermissionInfo& permission_info, // applies to permissions listed in |kPermissionType|. bool PageInfo::ShouldShowPermission( const PageInfo::PermissionInfo& info) const { diff --git a/patches/components-password_manager-core-browser-login_database.cc.patch b/patches/components-password_manager-core-browser-login_database.cc.patch index a4b1998955e3..1891eb522bd9 100644 --- a/patches/components-password_manager-core-browser-login_database.cc.patch +++ b/patches/components-password_manager-core-browser-login_database.cc.patch @@ -1,8 +1,8 @@ diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc -index 729330677790e17749b61acffe45e5c83fc3a766..c236962f44620da0c43c27c94b3cb9682010d012 100644 +index 579a2fca4e341f6419c91d91479aecbff074fda3..6c9e188bf3054a2e78bf426672973c761b19c7d0 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc -@@ -2173,6 +2173,7 @@ FormRetrievalResult LoginDatabase::StatementToForms( +@@ -2357,6 +2357,7 @@ FormRetrievalResult LoginDatabase::StatementToForms( EncryptionResult result = InitPasswordFormFromStatement( *statement, /*decrypt_and_fill_password_value=*/true, new_form.get()); diff --git a/patches/components-password_manager-core-browser-password_form_filling.cc.patch b/patches/components-password_manager-core-browser-password_form_filling.cc.patch index 3e358131713f..83195a62abb4 100644 --- a/patches/components-password_manager-core-browser-password_form_filling.cc.patch +++ b/patches/components-password_manager-core-browser-password_form_filling.cc.patch @@ -1,8 +1,8 @@ diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc -index 144a61f883521a181c98357e62e248e3d9904277..699babdeb0b1ed98cfc30d1a0ed4cb0fc9da5c38 100644 +index ca45a259d3c1a9947ef7458fdf8ea7657a2085ab..9c27826fe3ef188116dee951f082d446bf8821f9 100644 --- a/components/password_manager/core/browser/password_form_filling.cc +++ b/components/password_manager/core/browser/password_form_filling.cc -@@ -252,6 +252,7 @@ LikelyFormFilling SendFillInformationToRenderer( +@@ -236,6 +236,7 @@ LikelyFormFilling SendFillInformationToRenderer( bool wait_for_username = wait_for_username_reason != WaitForUsernameReason::kDontWait; diff --git a/patches/components-permissions-BUILD.gn.patch b/patches/components-permissions-BUILD.gn.patch index 799adb1a156f..d9d6656e5601 100644 --- a/patches/components-permissions-BUILD.gn.patch +++ b/patches/components-permissions-BUILD.gn.patch @@ -1,10 +1,10 @@ diff --git a/components/permissions/BUILD.gn b/components/permissions/BUILD.gn -index cba0ed139ae181b4ed5295b5b0f1a20bf4016e9f..0e3905a7c31c8a52d81f6c233cba0c23ca519a07 100644 +index 8de1e9259054621c85f296a5dc4b083857f9217d..7b949087a775a22248533334b0e304325c2671c6 100644 --- a/components/permissions/BUILD.gn +++ b/components/permissions/BUILD.gn -@@ -138,6 +138,7 @@ source_set("permissions") { - "contexts/geolocation_permission_context_system.h", - ] +@@ -141,6 +141,7 @@ source_set("permissions") { + if (!is_android && !is_ios) { + deps += [ "//components/guest_view/browser" ] } + import("//brave/components/permissions/sources.gni") sources += brave_components_permissions_sources deps += brave_components_permissions_deps if (is_android) { diff --git a/patches/components-permissions-permission_context_base.h.patch b/patches/components-permissions-permission_context_base.h.patch index 1b83f6565bee..af9a38ba9d9a 100644 --- a/patches/components-permissions-permission_context_base.h.patch +++ b/patches/components-permissions-permission_context_base.h.patch @@ -1,10 +1,10 @@ diff --git a/components/permissions/permission_context_base.h b/components/permissions/permission_context_base.h -index 35971997d12c7b532e3a666ecab04e9cf3562d06..3760250d90263da5743c0b88ce22076a5612fdde 100644 +index 5a4c04fd8a715b7dee5558a100865d344b945acc..216622bcedccdd9958c0b5d7b5bd527334ff56b3 100644 --- a/components/permissions/permission_context_base.h +++ b/components/permissions/permission_context_base.h -@@ -127,6 +127,7 @@ class PermissionContextBase : public content_settings::Observer { - void AddObserver(permissions::Observer* permission_observer); - void RemoveObserver(permissions::Observer* permission_observer); +@@ -130,6 +130,7 @@ class PermissionContextBase : public content_settings::Observer { + return content_settings_type_; + } + BRAVE_PERMISSION_CONTEXT_BASE_H_ protected: diff --git a/patches/components-permissions-permission_manager.cc.patch b/patches/components-permissions-permission_manager.cc.patch index 067a30951fac..a2e53a5abdf2 100644 --- a/patches/components-permissions-permission_manager.cc.patch +++ b/patches/components-permissions-permission_manager.cc.patch @@ -1,20 +1,20 @@ diff --git a/components/permissions/permission_manager.cc b/components/permissions/permission_manager.cc -index 354f19020944438c7f9e4ef61cb78b63031e1d70..b35b49d9540240f06f93cb41466ace22f1c6fa60 100644 +index 357c6ed0613de77411b9aea8b3c954e7d6cc0146..5089d8bef800c84f5bd77675814c52356e71a655 100644 --- a/components/permissions/permission_manager.cc +++ b/components/permissions/permission_manager.cc -@@ -325,6 +325,7 @@ void PermissionManager::RequestPermissionsFromCurrentDocument( +@@ -308,6 +308,7 @@ void PermissionManager::RequestPermissionsFromCurrentDocument( + base::OnceCallback&)> permission_status_callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - const GURL requesting_origin = -+ BRAVE_FORCED_REQUESTING_ORIGIN - PermissionUtil::GetLastCommittedOriginAsURL(render_frame_host); - RequestPermissionsInternal(permissions_types, render_frame_host, - requesting_origin, user_gesture, -@@ -377,6 +378,7 @@ PermissionManager::GetPermissionResultForCurrentDocument( ++ BRAVE_REQUEST_PERMISSION_FROM_CURRENT_DOCUMENT + RequestPermissionsInternal(render_frame_host, request_description, + std::move(permission_status_callback)); + } +@@ -355,6 +356,7 @@ PermissionManager::GetPermissionResultForCurrentDocument( PermissionUtil::PermissionTypeToContentSettingType(permission); const GURL requesting_origin = -+ BRAVE_FORCED_REQUESTING_ORIGIN ++ BRAVE_GET_PERMISSION_RESULT_FOR_CURRENT_DOCUMENT PermissionUtil::GetLastCommittedOriginAsURL(render_frame_host); const GURL embedding_origin = GetEmbeddingOrigin(render_frame_host, requesting_origin); diff --git a/patches/components-permissions-permission_uma_util.cc.patch b/patches/components-permissions-permission_uma_util.cc.patch index fc33f7bef8ec..886b157e21ae 100644 --- a/patches/components-permissions-permission_uma_util.cc.patch +++ b/patches/components-permissions-permission_uma_util.cc.patch @@ -1,5 +1,5 @@ diff --git a/components/permissions/permission_uma_util.cc b/components/permissions/permission_uma_util.cc -index 87ea482d898b8b5fc546cbfe327d706f18b09a71..8f484532265a7b23f0d8e56e4bf2ac1e25e59b78 100644 +index e44d704250bcf731528b1e8f9258cd5528c0c6bc..9800713e04832bb7dcdca91ab8de16f9b015ac0d 100644 --- a/components/permissions/permission_uma_util.cc +++ b/components/permissions/permission_uma_util.cc @@ -122,6 +122,7 @@ RequestTypeForUma GetUmaValueForRequestType(RequestType request_type) { diff --git a/patches/components-permissions-permission_util.cc.patch b/patches/components-permissions-permission_util.cc.patch index 93318f1fabc2..ec385f31eed8 100644 --- a/patches/components-permissions-permission_util.cc.patch +++ b/patches/components-permissions-permission_util.cc.patch @@ -1,8 +1,8 @@ diff --git a/components/permissions/permission_util.cc b/components/permissions/permission_util.cc -index cefae22f0b695bb50b2bb99d76c7207cbb9dbe82..a06ba1c2888183e418666f4f986585aa83c18c23 100644 +index 214e3be44aad3904dad2cff3eda7170c8e8a54db..82677c76234382b3da02453759e5d6f7c234d608 100644 --- a/components/permissions/permission_util.cc +++ b/components/permissions/permission_util.cc -@@ -312,6 +312,7 @@ ContentSettingsType PermissionUtil::PermissionTypeToContentSettingTypeSafe( +@@ -311,6 +311,7 @@ ContentSettingsType PermissionUtil::PermissionTypeToContentSettingTypeSafe( return ContentSettingsType::DISPLAY_CAPTURE; case PermissionType::NUM: break; diff --git a/patches/components-permissions-request_type.cc.patch b/patches/components-permissions-request_type.cc.patch index 75d26666efa6..baee1d9885f4 100644 --- a/patches/components-permissions-request_type.cc.patch +++ b/patches/components-permissions-request_type.cc.patch @@ -1,5 +1,5 @@ diff --git a/components/permissions/request_type.cc b/components/permissions/request_type.cc -index 26622d269e40c72329dcd5df28e397ed068e7660..47d478ce72f190b9d26f453c93bba3d202056780 100644 +index b2d7df958fce95f683b995e438e2b2116f68afb5..f760cb9858f33f2d6b21c5605fe5948fc6165941 100644 --- a/components/permissions/request_type.cc +++ b/components/permissions/request_type.cc @@ -397,6 +397,7 @@ const char* PermissionKeyForRequestType(permissions::RequestType request_type) { diff --git a/patches/components-policy-tools-template_writers-writer_configuration.py.patch b/patches/components-policy-tools-template_writers-writer_configuration.py.patch index 916731bff8ce..4e1056357a2a 100644 --- a/patches/components-policy-tools-template_writers-writer_configuration.py.patch +++ b/patches/components-policy-tools-template_writers-writer_configuration.py.patch @@ -1,5 +1,5 @@ diff --git a/components/policy/tools/template_writers/writer_configuration.py b/components/policy/tools/template_writers/writer_configuration.py -index 259e467fee3e9280c512db87ab8f48ed09c20ed3..1e6b41f7853e1a5062c6a9e9c527da9c06e6a9d6 100755 +index 02683fac018622069763cc4e9dd434dad59a5d73..ab5d00b4d4a03138c36fc3a888e2a9ab9941ee2f 100755 --- a/components/policy/tools/template_writers/writer_configuration.py +++ b/components/policy/tools/template_writers/writer_configuration.py @@ -131,3 +131,4 @@ def GetConfigurationForBuild(defines): diff --git a/patches/components-safe_browsing-core-common-safe_browsing_prefs.cc.patch b/patches/components-safe_browsing-core-common-safe_browsing_prefs.cc.patch index e1bf4bd45d61..eff51cef6af8 100644 --- a/patches/components-safe_browsing-core-common-safe_browsing_prefs.cc.patch +++ b/patches/components-safe_browsing-core-common-safe_browsing_prefs.cc.patch @@ -1,5 +1,5 @@ diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.cc b/components/safe_browsing/core/common/safe_browsing_prefs.cc -index 82c62b25c6bbb8b10db41fb6925c0fb227383e14..5f95a9d91de81bd1e9a3808d0ade4c3683950d2e 100644 +index 6bfd832d3c5b573f2dda62c335dc4759cca521f1..1c9018723d72c98351c539860ede6bcb0f34a5be 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.cc +++ b/components/safe_browsing/core/common/safe_browsing_prefs.cc @@ -181,6 +181,7 @@ bool IsSafeBrowsingEnabled(const PrefService& prefs) { diff --git a/patches/components-strings-BUILD.gn.patch b/patches/components-strings-BUILD.gn.patch index 80de2e2e164d..25bbb2e05850 100644 --- a/patches/components-strings-BUILD.gn.patch +++ b/patches/components-strings-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/components/strings/BUILD.gn b/components/strings/BUILD.gn -index cece9b840483a8e8fae0ce57112226dd657e4132..8d8c7cad42d480a240df4df777ed3f40406b212f 100644 +index 5ba77bfb9ff1d4a110802df37fbf11185088c837..c2813b12669a65471cbc3a412577bb8e57c7296e 100644 --- a/components/strings/BUILD.gn +++ b/components/strings/BUILD.gn @@ -50,6 +50,7 @@ grit("components_strings") { @@ -10,12 +10,3 @@ index cece9b840483a8e8fae0ce57112226dd657e4132..8d8c7cad42d480a240df4df777ed3f40 } if (is_android) { -@@ -62,7 +63,7 @@ if (is_android) { - } - - grit("components_chromium_strings") { -- source = "../components_chromium_strings.grd" -+ source = "../components_${branding_path_component}_strings.grd" - outputs = [ "grit/components_chromium_strings.h" ] - foreach(locale, all_chrome_locales) { - outputs += [ "components_chromium_strings_$locale.pak" ] diff --git a/patches/components-sync-BUILD.gn.patch b/patches/components-sync-BUILD.gn.patch index 93f53ee085c7..96e8100d3c71 100644 --- a/patches/components-sync-BUILD.gn.patch +++ b/patches/components-sync-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn -index 3e5ddf17284657f02db00e29ed9b9cfa16cc3657..adb231245aebc918015632732e612d304039201d 100644 +index 62d18bc96a386992cde393add46748bcab29c0e4..a067524c9ca3293cae04f9219b0c94cb8919c480 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn @@ -16,6 +16,7 @@ group("sync") { diff --git a/patches/components-sync-engine-model_type_worker.h.patch b/patches/components-sync-engine-model_type_worker.h.patch index b5052c565e19..ee7b5609dd5a 100644 --- a/patches/components-sync-engine-model_type_worker.h.patch +++ b/patches/components-sync-engine-model_type_worker.h.patch @@ -1,5 +1,5 @@ diff --git a/components/sync/engine/model_type_worker.h b/components/sync/engine/model_type_worker.h -index 008c09fac6d231d1e9d9a21d4928bc17f84d9ee2..9f97f203b5d85d8d766d8bd2d3c55f2918c47f91 100644 +index 8f224468d3c34a11738ac468572fb77e52a7d815..1d8183048347576f0095cf4893df61df14a1f762 100644 --- a/components/sync/engine/model_type_worker.h +++ b/components/sync/engine/model_type_worker.h @@ -207,6 +207,7 @@ class ModelTypeWorker : public UpdateHandler, diff --git a/patches/components-sync-protocol-proto_visitors.h.patch b/patches/components-sync-protocol-proto_visitors.h.patch index 94b9f5a61b41..3214fc6827ec 100644 --- a/patches/components-sync-protocol-proto_visitors.h.patch +++ b/patches/components-sync-protocol-proto_visitors.h.patch @@ -1,8 +1,8 @@ diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h -index b477edb0805791b699839adecca1685c2dce1c24..f09307cd27aca7f120eee5a08f88559294220fe2 100644 +index 0bff939fbe2275d2ccf8ba98329cb3fe9f5f83a0..178f292c619cfa7768afb16e3470dbbe8e7f5d96 100644 --- a/components/sync/protocol/proto_visitors.h +++ b/components/sync/protocol/proto_visitors.h -@@ -507,6 +507,7 @@ VISIT_PROTO_FIELDS(const sync_pb::DeviceInfoSpecifics& proto) { +@@ -509,6 +509,7 @@ VISIT_PROTO_FIELDS(const sync_pb::DeviceInfoSpecifics& proto) { VISIT(manufacturer); VISIT(last_updated_timestamp); VISIT(feature_fields); @@ -10,7 +10,7 @@ index b477edb0805791b699839adecca1685c2dce1c24..f09307cd27aca7f120eee5a08f885592 VISIT(sharing_fields); VISIT(invalidation_fields); VISIT(paask_fields); -@@ -521,6 +522,7 @@ VISIT_PROTO_FIELDS(const sync_pb::FeatureSpecificFields& proto) { +@@ -523,6 +524,7 @@ VISIT_PROTO_FIELDS(const sync_pb::FeatureSpecificFields& proto) { VISIT(send_tab_to_self_receiving_enabled); } diff --git a/patches/components-sync-service-BUILD.gn.patch b/patches/components-sync-service-BUILD.gn.patch index 972f26eb5ca2..6177e4be1554 100644 --- a/patches/components-sync-service-BUILD.gn.patch +++ b/patches/components-sync-service-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/components/sync/service/BUILD.gn b/components/sync/service/BUILD.gn -index 3b894c1bbb78911076b7efc4b43beb61621b51c8..af60a0e06a4d765d1da099c0efc638f4ec00f826 100644 +index 37c5c572d2022d90ebfd5fd26d8b70b5fdbc00dc..9c8791f6bad9019f90aedae36f21aad1e1d8309e 100644 --- a/components/sync/service/BUILD.gn +++ b/components/sync/service/BUILD.gn -@@ -112,4 +112,5 @@ static_library("service") { +@@ -115,4 +115,5 @@ static_library("service") { } configs += [ "//build/config/compiler:wexit_time_destructors" ] diff --git a/patches/components-sync-service-sync_service_impl.h.patch b/patches/components-sync-service-sync_service_impl.h.patch index c61e71343572..5aa078c11b5b 100644 --- a/patches/components-sync-service-sync_service_impl.h.patch +++ b/patches/components-sync-service-sync_service_impl.h.patch @@ -1,8 +1,8 @@ diff --git a/components/sync/service/sync_service_impl.h b/components/sync/service/sync_service_impl.h -index 398c5c2d25f2e45f3a273533bf8324b554a1a311..5264879e900a5c8c2482a9f2f287628653c659b8 100644 +index 8b2dad4af2fb2c44f04dba3c58cb6a2745a5f3ac..8e7b9a4e7c257ad2720c8f4b49284c827dd8b444 100644 --- a/components/sync/service/sync_service_impl.h +++ b/components/sync/service/sync_service_impl.h -@@ -247,6 +247,7 @@ class SyncServiceImpl : public SyncService, +@@ -254,6 +254,7 @@ class SyncServiceImpl : public SyncService, bool IsSyncFeatureConsideredRequested() const override; private: diff --git a/patches/components-sync_device_info-device_info_sync_bridge.cc.patch b/patches/components-sync_device_info-device_info_sync_bridge.cc.patch index 81973646a92f..018da6e7fb83 100644 --- a/patches/components-sync_device_info-device_info_sync_bridge.cc.patch +++ b/patches/components-sync_device_info-device_info_sync_bridge.cc.patch @@ -1,8 +1,8 @@ diff --git a/components/sync_device_info/device_info_sync_bridge.cc b/components/sync_device_info/device_info_sync_bridge.cc -index 5cf60ddb5a503ab81f3648dfe4cdda4ff368ffc0..2b37bdda4f05db9b8548b2668268a0b5950e4735 100644 +index 920ae87239a53664700c45217e9e9a8eafd63cae..177871b720e8aabd578c59d452271f88bf8ca534 100644 --- a/components/sync_device_info/device_info_sync_bridge.cc +++ b/components/sync_device_info/device_info_sync_bridge.cc -@@ -275,6 +275,7 @@ std::unique_ptr MakeLocalDeviceSpecifics( +@@ -276,6 +276,7 @@ std::unique_ptr MakeLocalDeviceSpecifics( GetSpecificsFieldNumberFromModelType(data_type)); } @@ -10,7 +10,7 @@ index 5cf60ddb5a503ab81f3648dfe4cdda4ff368ffc0..2b37bdda4f05db9b8548b2668268a0b5 return specifics; } -@@ -477,6 +478,7 @@ absl::optional DeviceInfoSyncBridge::ApplyIncrementalSyncChanges( +@@ -478,6 +479,7 @@ absl::optional DeviceInfoSyncBridge::ApplyIncrementalSyncChanges( for (const std::unique_ptr& change : entity_changes) { const std::string guid = change->storage_key(); @@ -18,7 +18,7 @@ index 5cf60ddb5a503ab81f3648dfe4cdda4ff368ffc0..2b37bdda4f05db9b8548b2668268a0b5 // Reupload local device if it was deleted from the server. if (local_cache_guid_ == guid && change->type() == EntityChange::ACTION_DELETE) { -@@ -487,7 +489,7 @@ absl::optional DeviceInfoSyncBridge::ApplyIncrementalSyncChanges( +@@ -488,7 +490,7 @@ absl::optional DeviceInfoSyncBridge::ApplyIncrementalSyncChanges( // Ignore any remote changes that have a cache guid that is or was this // local device. if (device_info_prefs_->IsRecentLocalCacheGuid(guid)) { @@ -27,7 +27,7 @@ index 5cf60ddb5a503ab81f3648dfe4cdda4ff368ffc0..2b37bdda4f05db9b8548b2668268a0b5 } if (change->type() == EntityChange::ACTION_DELETE) { -@@ -747,6 +749,7 @@ void DeviceInfoSyncBridge::OnReadAllMetadata( +@@ -750,6 +752,7 @@ void DeviceInfoSyncBridge::OnReadAllMetadata( return; } @@ -35,10 +35,10 @@ index 5cf60ddb5a503ab81f3648dfe4cdda4ff368ffc0..2b37bdda4f05db9b8548b2668268a0b5 // In the regular case for sync being disabled, wait for MergeFullSyncData() // before initializing the LocalDeviceInfoProvider. if (!syncer::IsInitialSyncDone( -@@ -981,6 +984,7 @@ DeviceInfoSyncBridge::CountActiveDevicesByType() const { - } +@@ -986,6 +989,7 @@ DeviceInfoSyncBridge::CountActiveDevicesByType() const { void DeviceInfoSyncBridge::ExpireOldEntries() { + TRACE_EVENT0("sync", "DeviceInfoSyncBridge::ExpireOldEntries"); + BRAVE_SKIP_EXPIRE_OLD_ENTRIES const base::Time expiration_threshold = base::Time::Now() - kExpirationThreshold; diff --git a/patches/components-variations-variations_seed_store.cc.patch b/patches/components-variations-variations_seed_store.cc.patch index f16bc764eb1f..76d3bc25b6f1 100644 --- a/patches/components-variations-variations_seed_store.cc.patch +++ b/patches/components-variations-variations_seed_store.cc.patch @@ -1,5 +1,5 @@ diff --git a/components/variations/variations_seed_store.cc b/components/variations/variations_seed_store.cc -index 823d77d73aa641949258ed5a00e2cc4e58a418f6..b4f6286b1ee37064240f06a20cfca70118b212d7 100644 +index b12dd017dc36bd1fc8d646a40436dcab3c17e3d7..6b8eda118284cb89bee5e5caaeeb6ec97bdb79c8 100644 --- a/components/variations/variations_seed_store.cc +++ b/components/variations/variations_seed_store.cc @@ -51,6 +51,7 @@ const base::FeatureParam kVariationsAsyncProcessing{ diff --git a/patches/content-browser-browser_main_loop.h.patch b/patches/content-browser-browser_main_loop.h.patch index 74a4cbc818dc..a08fad897997 100644 --- a/patches/content-browser-browser_main_loop.h.patch +++ b/patches/content-browser-browser_main_loop.h.patch @@ -1,8 +1,8 @@ diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h -index b25487927b523592c5097b6b8bb818350f81603a..3b70575d29fe2338ba49dcb212ee7aae0cfcfc79 100644 +index fa0803bf3322cc676ceae985d4c2006bfbd8d5d0..6cb59f673afd25053486dbd68f4f13c3c9087bbc 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h -@@ -160,6 +160,7 @@ class CONTENT_EXPORT BrowserMainLoop { +@@ -161,6 +161,7 @@ class CONTENT_EXPORT BrowserMainLoop { void RunMainMessageLoop(); // Performs the pre-shutdown steps. diff --git a/patches/content-browser-gpu-gpu_internals_ui.cc.patch b/patches/content-browser-gpu-gpu_internals_ui.cc.patch index b00aea3de582..c12bd33b4e22 100644 --- a/patches/content-browser-gpu-gpu_internals_ui.cc.patch +++ b/patches/content-browser-gpu-gpu_internals_ui.cc.patch @@ -1,5 +1,5 @@ diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc -index 90811bf43cbd1c9959799738c655e8adbbdf0008..a3685d52fbcf86d917e0c009117fed6733334c57 100644 +index e8c3a4e889aeee0fb7d3ef9aa9ff88f4448f96cb..e016a727120fe5ae3d8119c830c1dc1a126fd634 100644 --- a/content/browser/gpu/gpu_internals_ui.cc +++ b/content/browser/gpu/gpu_internals_ui.cc @@ -838,6 +838,7 @@ base::Value::Dict GpuMessageHandler::GetClientInfo() { diff --git a/patches/content-browser-renderer_host-navigation_controller_impl.cc.patch b/patches/content-browser-renderer_host-navigation_controller_impl.cc.patch index 80afdf7ffadb..4bfac444f375 100644 --- a/patches/content-browser-renderer_host-navigation_controller_impl.cc.patch +++ b/patches/content-browser-renderer_host-navigation_controller_impl.cc.patch @@ -1,8 +1,8 @@ diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc -index af9f3a0744d1bfd5471bbf42aa7b8498e5fcd8bc..e671837f3e93c30c8c649dfe209ef70a87d0bca8 100644 +index 6ef5de7eb9f4933b0d0bb3f25d2c5803bb1970f8..a15505ecfe4ba61903d0a14a2495ce763834873d 100644 --- a/content/browser/renderer_host/navigation_controller_impl.cc +++ b/content/browser/renderer_host/navigation_controller_impl.cc -@@ -3591,16 +3591,17 @@ base::WeakPtr NavigationControllerImpl::NavigateWithoutEntry( +@@ -3593,16 +3593,17 @@ base::WeakPtr NavigationControllerImpl::NavigateWithoutEntry( // Note: we intentionally leave the pending entry in place for renderer debug // URLs, unlike the cases below where we clear it if the navigation doesn't // proceed. diff --git a/patches/content-browser-renderer_host-navigation_request.cc.patch b/patches/content-browser-renderer_host-navigation_request.cc.patch index 7e230028d413..a073fff2e849 100644 --- a/patches/content-browser-renderer_host-navigation_request.cc.patch +++ b/patches/content-browser-renderer_host-navigation_request.cc.patch @@ -1,8 +1,8 @@ diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc -index da87a4f823d6fa36589b6efc7e3b381fdd07b11c..366c4fd83d4a15aa2cd0de3dcccc03fff8a30a53 100644 +index e91fb6b203b55d4937e9f4b4ed8fd5e8efb5aa10..4f468007f087ae6a042500988a82cad8326a6787 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc -@@ -3192,6 +3192,7 @@ void NavigationRequest::OnRequestRedirected( +@@ -3268,6 +3268,7 @@ void NavigationRequest::OnRequestRedirected( common_params_->url = redirect_info.new_url; common_params_->method = redirect_info.new_method; common_params_->referrer->url = GURL(redirect_info.new_referrer); @@ -10,7 +10,7 @@ index da87a4f823d6fa36589b6efc7e3b381fdd07b11c..366c4fd83d4a15aa2cd0de3dcccc03ff common_params_->referrer = Referrer::SanitizeForRequest( common_params_->url, *common_params_->referrer); -@@ -4807,6 +4808,7 @@ void NavigationRequest::OnStartChecksComplete( +@@ -4883,6 +4884,7 @@ void NavigationRequest::OnStartChecksComplete( headers.MergeFrom(TakeModifiedRequestHeaders()); begin_params_->headers = headers.ToString(); diff --git a/patches/content-browser-renderer_host-render_frame_host_impl.cc.patch b/patches/content-browser-renderer_host-render_frame_host_impl.cc.patch index fd6e861e3b11..e26304730111 100644 --- a/patches/content-browser-renderer_host-render_frame_host_impl.cc.patch +++ b/patches/content-browser-renderer_host-render_frame_host_impl.cc.patch @@ -1,8 +1,8 @@ diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc -index 8525270e85ccb259bc8fb1d720a2882c33d4f25b..f751eb01235e78798d95a372e0cd104fe83b6c38 100644 +index ad0d9cd11022f4f35e717efc088593df41d46496..03f3557f459b75da5d07e992290587448b71ff42 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc -@@ -8105,6 +8105,8 @@ void RenderFrameHostImpl::CreateNewWindow( +@@ -8255,6 +8255,8 @@ void RenderFrameHostImpl::CreateNewWindow( dom_storage_context, params->session_storage_namespace_id); } diff --git a/patches/content-browser-resources-gpu-info_view.ts.patch b/patches/content-browser-resources-gpu-info_view.ts.patch index ed5025bedbaa..ec88c8aff520 100644 --- a/patches/content-browser-resources-gpu-info_view.ts.patch +++ b/patches/content-browser-resources-gpu-info_view.ts.patch @@ -1,12 +1,12 @@ diff --git a/content/browser/resources/gpu/info_view.ts b/content/browser/resources/gpu/info_view.ts -index 0b91cc130f46ffe135b6ef10760c5fa08e7736ad..696c48e7aef95f8b77b33b86e6fd2193b6053a3a 100644 +index 918bf8b4f710f0de5302266098faace06aab83b6..aea6893096e52141177042b79b24b8757d906c39 100644 --- a/content/browser/resources/gpu/info_view.ts +++ b/content/browser/resources/gpu/info_view.ts -@@ -91,6 +91,7 @@ export class InfoViewElement extends CustomElement { +@@ -537,6 +537,7 @@ export class InfoViewElement extends CustomElement { value: clientInfo.graphics_backend, }, {description: 'Command Line', value: clientInfo.command_line}, + {description: 'Executable path', value: clientInfo.executable_path}, ]); } else { - this.setText_('client-info', '... loading...'); + sections.clientInfo.list.textContent = '... loading ...'; diff --git a/patches/content-browser-web_contents-web_contents_impl.cc.patch b/patches/content-browser-web_contents-web_contents_impl.cc.patch index f56646ef2036..207d94887fd2 100644 --- a/patches/content-browser-web_contents-web_contents_impl.cc.patch +++ b/patches/content-browser-web_contents-web_contents_impl.cc.patch @@ -1,8 +1,8 @@ diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc -index b5bb5e16086d47130f5e810d1b30538ca818b908..ff47a6d9f69a1b86ad810cf96d9ebb8d2491e52d 100644 +index 6f1581c517bf6c4526d7831d50ce2ad0bc8d7531..32266e1af0324e7d3a1b50aeeab4cfd6f5828300 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc -@@ -4320,7 +4320,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( +@@ -4326,7 +4326,7 @@ FrameTree* WebContentsImpl::CreateNewWindow( // Save the window for later if we're not suppressing the opener (since it // will be shown immediately). diff --git a/patches/content-common-BUILD.gn.patch b/patches/content-common-BUILD.gn.patch index 46cfa9ef4b7f..1ea778b25b57 100644 --- a/patches/content-common-BUILD.gn.patch +++ b/patches/content-common-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn -index dce27cfa39b52e39a95cee658584ed80ab1953ef..430b46e1c632a9812f080e7f6e547b11748c046b 100644 +index 9c9f6d58a8e5c1ed14eb60c722667d1a24d2c6fa..3470d80982a94b943f611c37ad5fe6ce6deedea0 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn @@ -67,6 +67,7 @@ source_set("common") { diff --git a/patches/content-common-frame.mojom.patch b/patches/content-common-frame.mojom.patch index 1ed5b36bbcd9..69b219889547 100644 --- a/patches/content-common-frame.mojom.patch +++ b/patches/content-common-frame.mojom.patch @@ -1,8 +1,8 @@ diff --git a/content/common/frame.mojom b/content/common/frame.mojom -index a1757960b139dea126e34776e9ec7768d9e3d89d..aa93ae3c923a2cbb7c67a53654cec777b635d31e 100644 +index 3ddc93e18d353d5af31e28f8f8e682ea813db21c..2f968ed079f6cb04b6a90f0f4bc4dfa360f5bdf3 100644 --- a/content/common/frame.mojom +++ b/content/common/frame.mojom -@@ -582,6 +582,7 @@ struct CreateNewWindowParams { +@@ -574,6 +574,7 @@ struct CreateNewWindowParams { // Whether the opener will be suppressed in the new window, in which case // scripting the new window is not allowed. bool opener_suppressed; diff --git a/patches/content-public-browser-content_browser_client.h.patch b/patches/content-public-browser-content_browser_client.h.patch index 8ff81e9e09a8..cb5186a894f7 100644 --- a/patches/content-public-browser-content_browser_client.h.patch +++ b/patches/content-public-browser-content_browser_client.h.patch @@ -1,8 +1,8 @@ diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h -index 5fec5acd6fac364e815014ac0166c6f241acae37..8b8264c307ee5059570ed99c17b307e392c89ef7 100644 +index a6e922be7e68644ad1cfe64462712c0430c6749a..2c36598384733d9ad0d8e37c9c068a49466c2b65 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h -@@ -2196,6 +2196,7 @@ class CONTENT_EXPORT ContentBrowserClient { +@@ -2216,6 +2216,7 @@ class CONTENT_EXPORT ContentBrowserClient { virtual ui::AXMode GetAXModeForBrowserContext( BrowserContext* browser_context); diff --git a/patches/content-renderer-render_frame_impl.cc.patch b/patches/content-renderer-render_frame_impl.cc.patch index 056d98f2edfa..287ef57fa192 100644 --- a/patches/content-renderer-render_frame_impl.cc.patch +++ b/patches/content-renderer-render_frame_impl.cc.patch @@ -1,5 +1,5 @@ diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc -index 94d3c751277e0ce6882d0cbc7e38c2e4eb6af44f..bd3224e6f9f680460535d7f3fc6e9c80fd501621 100644 +index ab92d5b8f710661d8b1c863423f0c0f7928646ba..36fbca713f83be765162aae67f85f7d90868449b 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -4531,6 +4531,7 @@ bool RenderFrameImpl::ShouldUseUserAgentOverride() const { diff --git a/patches/content-renderer-render_thread_impl.cc.patch b/patches/content-renderer-render_thread_impl.cc.patch index 29aeec9585d5..3cebd3ee8f25 100644 --- a/patches/content-renderer-render_thread_impl.cc.patch +++ b/patches/content-renderer-render_thread_impl.cc.patch @@ -1,8 +1,8 @@ diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc -index d1f8638d390858b0872c56a62168acb7eef04db4..04a021b958eff1271718f372a88ec09930c63ffd 100644 +index 328ed025f6b71c34f2855a5a2983dee7e7081c11..fe6c1d2f3266faf7f5239bbfb59e3cdb187593ca 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc -@@ -942,6 +942,7 @@ void RenderThreadImpl::InitializeRenderer( +@@ -941,6 +941,7 @@ void RenderThreadImpl::InitializeRenderer( } void RenderThreadImpl::RegisterSchemes() { diff --git a/patches/crypto-aead.cc.patch b/patches/crypto-aead.cc.patch index 1f1c2967fd08..2c2043b2447f 100644 --- a/patches/crypto-aead.cc.patch +++ b/patches/crypto-aead.cc.patch @@ -1,5 +1,5 @@ diff --git a/crypto/aead.cc b/crypto/aead.cc -index bb556f8afb92f4b57bf8da7c5c5b2629841e80aa..97c32028f288d30e366ade9ad0b4216984f0e9f8 100644 +index b3b26d9553bd230fd5049e13f11e1760fd9efa7f..eb5ef899165aaf4da8e67deb286ebf8276172071 100644 --- a/crypto/aead.cc +++ b/crypto/aead.cc @@ -130,6 +130,7 @@ size_t Aead::KeyLength() const { diff --git a/patches/extensions-browser-api-web_request-extension_web_request_event_router.cc.patch b/patches/extensions-browser-api-web_request-extension_web_request_event_router.cc.patch index b2b59125e81e..f24bb30ac2b2 100644 --- a/patches/extensions-browser-api-web_request-extension_web_request_event_router.cc.patch +++ b/patches/extensions-browser-api-web_request-extension_web_request_event_router.cc.patch @@ -1,12 +1,12 @@ diff --git a/extensions/browser/api/web_request/extension_web_request_event_router.cc b/extensions/browser/api/web_request/extension_web_request_event_router.cc -index 7a29adc72df19d359272bb37fa55d8b9b5cb9912..6eff2126c6a85481be86fcb3526eb224e5b20119 100644 +index a8f8bf4e930361ca1f348b3684b8c0461a840ad3..eb134802a57d4ec2687172b09907a98feb23a16b 100644 --- a/extensions/browser/api/web_request/extension_web_request_event_router.cc +++ b/extensions/browser/api/web_request/extension_web_request_event_router.cc -@@ -1168,6 +1168,7 @@ ExtensionWebRequestEventRouter::OnAuthRequired( - const net::AuthChallengeInfo& auth_info, - AuthCallback callback, - net::AuthCredentials* credentials) { +@@ -1183,6 +1183,7 @@ ExtensionWebRequestEventRouter::OnAuthRequired( + *request)) { + return AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_NO_ACTION; + } + BRAVE_EXTENSION_WEB_REQUEST_EVENT_ROUTER_ON_AUTH_REQUIRED - // No browser_context means that this is for authentication challenges in the - // system context. Skip in that case. Also skip sensitive requests. - if (!browser_context || + + int extra_info_spec = 0; + RawListeners listeners = GetMatchingListeners( diff --git a/patches/extensions-browser-extension_creator.cc.patch b/patches/extensions-browser-extension_creator.cc.patch index 802eec2968a7..237bf53ddec8 100644 --- a/patches/extensions-browser-extension_creator.cc.patch +++ b/patches/extensions-browser-extension_creator.cc.patch @@ -1,8 +1,8 @@ diff --git a/extensions/browser/extension_creator.cc b/extensions/browser/extension_creator.cc -index 3f982183b3b457fa2c72f1893ac752b3fe4b302f..91de0968f32ec8f57780cfc25334810be7436050 100644 +index fba56640051f8489411639531619ec57844f889a..8992513db8bdd4c6d65fdac806eaa05d3e549917 100644 --- a/extensions/browser/extension_creator.cc +++ b/extensions/browser/extension_creator.cc -@@ -223,7 +223,7 @@ bool ExtensionCreator::CreateCrx( +@@ -211,7 +211,7 @@ bool ExtensionCreator::CreateCrx( result = crx_file::CreateCrxWithVerifiedContentsInHeader( crx_path, zip_path, private_key, compressed_verified_contents.value()); } else { diff --git a/patches/extensions-common-api-_api_features.json.patch b/patches/extensions-common-api-_api_features.json.patch index 6939b73a68b0..4fccbb1aa793 100644 --- a/patches/extensions-common-api-_api_features.json.patch +++ b/patches/extensions-common-api-_api_features.json.patch @@ -1,8 +1,8 @@ diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json -index 0c8b15e7f7b7e46208e0d221beb64576482d3390..c02e373ba5d0ff14cf78731a66e781cd632bb997 100644 +index ddf66ad5d842b1af5811c1ab521700396d01813f..7e246c45b9dff2cc8ddeb1697c9b0713df3294c0 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json -@@ -634,6 +634,7 @@ +@@ -635,6 +635,7 @@ "matches": [ "chrome://password-change/*", "chrome://file-manager/*" diff --git a/patches/headless-BUILD.gn.patch b/patches/headless-BUILD.gn.patch new file mode 100644 index 000000000000..6b54e8f6fe15 --- /dev/null +++ b/patches/headless-BUILD.gn.patch @@ -0,0 +1,13 @@ +diff --git a/headless/BUILD.gn b/headless/BUILD.gn +index e0ec74566e0474012ac660fc8929853219f5fcc7..67a046ea4135e74ae0e44f4e0bffc015585ec3bf 100644 +--- a/headless/BUILD.gn ++++ b/headless/BUILD.gn +@@ -96,7 +96,7 @@ repack("resource_pack_strings") { + if (is_chrome_branded) { + sources += [ "${root_gen_dir}/components/strings/components_google_chrome_strings_en-US.pak" ] + } else { +- sources += [ "${root_gen_dir}/components/strings/components_chromium_strings_en-US.pak" ] ++ sources += [ "${root_gen_dir}/components/strings/components_${branding_path_product}_strings_en-US.pak" ] + } + + deps = [ diff --git a/patches/ios-chrome-app-BUILD.gn.patch b/patches/ios-chrome-app-BUILD.gn.patch index 541fe4bc90e1..88a94187d867 100644 --- a/patches/ios-chrome-app-BUILD.gn.patch +++ b/patches/ios-chrome-app-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn -index 2408035d9a2e9aeb0a652b5a7f9feb19baceb928..06334ddd4279be6a37c024e1aee13c680896b44f 100644 +index d104fc75d518428acdab00ad9881c2245b114704..f23b7177470d753c078ca4f15e62d2e149883a30 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn -@@ -727,8 +727,7 @@ chrome_app("chrome") { +@@ -729,8 +729,7 @@ chrome_app("chrome") { # (see https://crbug.com/1394553 for details of the build failure). This # is a stop-gap solution. if (target_environment == "catalyst" || diff --git a/patches/ios-chrome-browser-shared-model-prefs-browser_prefs.mm.patch b/patches/ios-chrome-browser-shared-model-prefs-browser_prefs.mm.patch index b0856e33abd5..764cdf16c7e3 100644 --- a/patches/ios-chrome-browser-shared-model-prefs-browser_prefs.mm.patch +++ b/patches/ios-chrome-browser-shared-model-prefs-browser_prefs.mm.patch @@ -1,26 +1,28 @@ diff --git a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm -index 1fa0cd98c343546757fbbf08468e43eb786c250f..38744f944c6b95e1cb5fd04ef9e42724f20cea61 100644 +index 6ee67529756cf1c2856253cc5ff7a3c4997ab3a4..1852a7e73224fb37495329a172eeb767436a8e1b 100644 --- a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm +++ b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm -@@ -299,6 +299,7 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) { - prefs::kIosSafetyCheckManagerSafeBrowsingCheckResult, - NameForSafetyCheckState(SafeBrowsingSafetyCheckState::kDefault), - PrefRegistry::LOSSY_PREF); +@@ -322,6 +322,7 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) { + // refactored to use the new Safety Check Manager. + registry->RegisterTimePref(prefs::kIosSettingsSafetyCheckLastRunTime, + base::Time()); + BRAVE_REGISTER_LOCAL_STATE_PREFS } void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { -@@ -479,6 +480,7 @@ void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { - // Register pref used to detect addresses in web page - registry->RegisterBooleanPref(prefs::kDetectAddressesEnabled, true); - registry->RegisterBooleanPref(prefs::kDetectAddressesAccepted, false); +@@ -512,6 +513,7 @@ void RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { + + // Register prefs used to skip too frequent History Sync Opt-In prompt. + history_sync::RegisterBrowserStatePrefs(registry); + BRAVE_REGISTER_BROWSER_STATE_PREFS } // This method should be periodically pruned of year+ old migrations. -@@ -567,4 +569,5 @@ void MigrateObsoleteBrowserStatePrefs(PrefService* prefs) { +@@ -600,6 +602,7 @@ void MigrateObsoleteBrowserStatePrefs(PrefService* prefs) { invalidation::InvalidatorRegistrarWithMemory::ClearDeprecatedPrefs(prefs); invalidation::PerUserTopicSubscriptionManager::ClearDeprecatedPrefs(prefs); invalidation::FCMInvalidationService::ClearDeprecatedPrefs(prefs); + BRAVE_MIGRATE_OBSOLETE_BROWSER_STATE_PREFS } + + void MigrateObsoleteUserDefault(void) { diff --git a/patches/ios-chrome-browser-sync-sync_service_factory.mm.patch b/patches/ios-chrome-browser-sync-sync_service_factory.mm.patch index b9bc8194fd69..871b2cd661df 100644 --- a/patches/ios-chrome-browser-sync-sync_service_factory.mm.patch +++ b/patches/ios-chrome-browser-sync-sync_service_factory.mm.patch @@ -1,8 +1,8 @@ diff --git a/ios/chrome/browser/sync/sync_service_factory.mm b/ios/chrome/browser/sync/sync_service_factory.mm -index eba86ca628053db3fa07b231d30c9902589bc643..451fce16032a81256848a5908201e5e8c131c428 100644 +index de6b49b5ab55d37cd55b57877cccfcf994af0628..ee4938602728ac1267952d7de9291a3bceab1bd8 100644 --- a/ios/chrome/browser/sync/sync_service_factory.mm +++ b/ios/chrome/browser/sync/sync_service_factory.mm -@@ -170,7 +170,7 @@ std::unique_ptr SyncServiceFactory::BuildServiceInstanceFor( +@@ -97,7 +97,7 @@ std::unique_ptr BuildSyncService(web::BrowserState* context) { init_params.debug_identifier = browser_state->GetDebugName(); auto sync_service = diff --git a/patches/net-BUILD.gn.patch b/patches/net-BUILD.gn.patch index c8c0943eb9f6..c292ca35a1e2 100644 --- a/patches/net-BUILD.gn.patch +++ b/patches/net-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/net/BUILD.gn b/net/BUILD.gn -index a57b48653375fc907da68b94b5e87adcc95aa25a..e70785191f2faeaa764903e5658ac8e8fb6e6f6b 100644 +index f0493cfd8456000f88f1536e908fdc8ace227a28..06daf7bb2625610670494a295c73d1d206179e37 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn -@@ -1158,6 +1158,7 @@ component("net") { +@@ -1160,6 +1160,7 @@ component("net") { "reporting/reporting_uploader.h", ] } diff --git a/patches/net-cookies-canonical_cookie.cc.patch b/patches/net-cookies-canonical_cookie.cc.patch index ed1ee12908f2..1436df41dcc5 100644 --- a/patches/net-cookies-canonical_cookie.cc.patch +++ b/patches/net-cookies-canonical_cookie.cc.patch @@ -1,5 +1,5 @@ diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc -index edb3e8b305538be9e58dea5b3dd53e4aae30a67d..d9c6edf446226dde8b0c75f07e384ee12bd190da 100644 +index 089443aab299000b7a10b42b90f3367318aa7730..2469311431c23816a773536d3eadfbe48dfe8603 100644 --- a/net/cookies/canonical_cookie.cc +++ b/net/cookies/canonical_cookie.cc @@ -514,6 +514,7 @@ base::Time CanonicalCookie::ValidateAndAdjustExpiryDate( @@ -7,6 +7,6 @@ index edb3e8b305538be9e58dea5b3dd53e4aae30a67d..d9c6edf446226dde8b0c75f07e384ee1 fixed_creation_date = base::Time::Now(); } + BRAVE_CANONICAL_COOKIE_VALIDATE_AND_ADJUST_EXPIRY_DATE - if (base::FeatureList::IsEnabled(features::kClampCookieExpiryTo400Days)) { - base::Time maximum_expiry_date = fixed_creation_date + base::Days(400); - if (expiry_date > maximum_expiry_date) + base::Time maximum_expiry_date = fixed_creation_date + base::Days(400); + if (expiry_date > maximum_expiry_date) { + return maximum_expiry_date; diff --git a/patches/sandbox-policy-win-sandbox_win.cc.patch b/patches/sandbox-policy-win-sandbox_win.cc.patch index ab6695829856..feaae60b2ad2 100644 --- a/patches/sandbox-policy-win-sandbox_win.cc.patch +++ b/patches/sandbox-policy-win-sandbox_win.cc.patch @@ -1,8 +1,8 @@ diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc -index 2ee0182088f41846f352fae0b67fc90448855355..1a093e5d75a3ccfae240ca493628e3c5ce762af3 100644 +index 3add6ba6997a36738bd0421641c91c477936241a..5967d028bed18f1b1e4fdd108b537bb24704216a 100644 --- a/sandbox/policy/win/sandbox_win.cc +++ b/sandbox/policy/win/sandbox_win.cc -@@ -711,6 +711,7 @@ ResultCode LaunchWithoutSandbox( +@@ -717,6 +717,7 @@ ResultCode LaunchWithoutSandbox( base::Process* process) { base::LaunchOptions options; options.handles_to_inherit = handles_to_inherit; diff --git a/patches/sandbox-win-BUILD.gn.patch b/patches/sandbox-win-BUILD.gn.patch index 8766d547c9dc..c6a0f72eb5d8 100644 --- a/patches/sandbox-win-BUILD.gn.patch +++ b/patches/sandbox-win-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn -index e9d67c43a84d6b1cf60743c4814b9e74e26a4e02..669883c32b824d615053dcc39823d320556b39d8 100644 +index 1d802abaf95a75bae4f778eeda26d01f0c056698..04e4aedac233266b3b38e082f0bc71af00f89b35 100644 --- a/sandbox/win/BUILD.gn +++ b/sandbox/win/BUILD.gn @@ -186,6 +186,7 @@ static_library("sandbox") { diff --git a/patches/services-network-cookie_manager.cc.patch b/patches/services-network-cookie_manager.cc.patch index c7d5fca8d8fa..e695fb2ec4e7 100644 --- a/patches/services-network-cookie_manager.cc.patch +++ b/patches/services-network-cookie_manager.cc.patch @@ -1,8 +1,8 @@ diff --git a/services/network/cookie_manager.cc b/services/network/cookie_manager.cc -index abe47939a03cec9aa08a46c49df569ff6c4c5763..988f7ba6bdefbc972ec78f8e445a4f575e7d62a2 100644 +index 6c804ec1092afbec3e23759077e2e9b02f8c136f..003f2d437f72a56f672522d5fbe2b136f96084c8 100644 --- a/services/network/cookie_manager.cc +++ b/services/network/cookie_manager.cc -@@ -389,6 +389,7 @@ CookieDeletionInfo DeletionFilterToInfo(mojom::CookieDeletionFilterPtr filter) { +@@ -406,6 +406,7 @@ CookieDeletionInfo DeletionFilterToInfo(mojom::CookieDeletionFilterPtr filter) { delete_info.name = std::move(filter->cookie_name); delete_info.url = std::move(filter->url); delete_info.host = std::move(filter->host_name); diff --git a/patches/services-network-cors-cors_url_loader.cc.patch b/patches/services-network-cors-cors_url_loader.cc.patch index afa5bc670188..b04d5c647087 100644 --- a/patches/services-network-cors-cors_url_loader.cc.patch +++ b/patches/services-network-cors-cors_url_loader.cc.patch @@ -1,8 +1,8 @@ diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc -index d0614c83b2bb5b0fd58b497f69fdc7be2a54045d..505c29dc7a4d7e725a641845302e3c19eb1cae77 100644 +index 9314bc134c9a47d362e0a7ca27be2a1f1e54ae03..b2ae6c80403477e60c755fd333ca44de4779d0f0 100644 --- a/services/network/cors/cors_url_loader.cc +++ b/services/network/cors/cors_url_loader.cc -@@ -805,6 +805,7 @@ void CorsURLLoader::StartRequest() { +@@ -820,6 +820,7 @@ void CorsURLLoader::StartRequest() { (fetch_cors_flag_ || (request_.method != net::HttpRequestHeaders::kGetMethod && request_.method != net::HttpRequestHeaders::kHeadMethod))) { diff --git a/patches/services-network-public-cpp-cors-cors.cc.patch b/patches/services-network-public-cpp-cors-cors.cc.patch index 0f8814f521f7..312f7bc793cc 100644 --- a/patches/services-network-public-cpp-cors-cors.cc.patch +++ b/patches/services-network-public-cpp-cors-cors.cc.patch @@ -1,5 +1,5 @@ diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc -index e72cb977f6a29a3767f103ef29e3df2d31b23048..3fc6f27c4c2aad35319b7bf66a75372555d7de92 100644 +index 391588c14d4ac182a60e525bd811211c75163ced..0782d710418416b0b90c9e4ad66ffc5c1bc42ca7 100644 --- a/services/network/public/cpp/cors/cors.cc +++ b/services/network/public/cpp/cors/cors.cc @@ -326,6 +326,7 @@ bool IsCorsSafelistedHeader(const std::string& name, const std::string& value) { diff --git a/patches/third_party-blink-common-client_hints-client_hints.cc.patch b/patches/third_party-blink-common-client_hints-client_hints.cc.patch index fe2a3fc0bac3..77f4c0b29dfa 100644 --- a/patches/third_party-blink-common-client_hints-client_hints.cc.patch +++ b/patches/third_party-blink-common-client_hints-client_hints.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/common/client_hints/client_hints.cc b/third_party/blink/common/client_hints/client_hints.cc -index 5c0d77d82bdd251d3c21d8ae594d2ede534255c1..8c566149df04fed84862b4e6cf020514f7f61236 100644 +index 8172639a0a556ccde3fa878336ad48702919452b..be05ae342d28ecb24fdba1216e1ceb19df09f491 100644 --- a/third_party/blink/common/client_hints/client_hints.cc +++ b/third_party/blink/common/client_hints/client_hints.cc -@@ -103,6 +103,7 @@ const PolicyFeatureToClientHintMap& GetPolicyFeatureToClientHintMap() { +@@ -105,6 +105,7 @@ const PolicyFeatureToClientHintMap& GetPolicyFeatureToClientHintMap() { } bool IsClientHintSentByDefault(network::mojom::WebClientHintsType type) { diff --git a/patches/third_party-blink-renderer-bindings-BUILD.gn.patch b/patches/third_party-blink-renderer-bindings-BUILD.gn.patch index fce6cee38cf4..59d65cd2650b 100644 --- a/patches/third_party-blink-renderer-bindings-BUILD.gn.patch +++ b/patches/third_party-blink-renderer-bindings-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/bindings/BUILD.gn b/third_party/blink/renderer/bindings/BUILD.gn -index df522f5c4245f754c0197c4181869202fabb43c0..ccc0b7db8c25be34da985bb6520ece22bd133f52 100644 +index 98ab27b33cd85fa68432b9d0aa5489447f1a6ec2..a61d36f2e6453fe11f3bef2fa4384cfb3f81143e 100644 --- a/third_party/blink/renderer/bindings/BUILD.gn +++ b/third_party/blink/renderer/bindings/BUILD.gn -@@ -174,6 +174,7 @@ template("generate_bindings") { +@@ -173,6 +173,7 @@ template("generate_bindings") { args += invoker.targets deps = [ ":web_idl_database" ] diff --git a/patches/third_party-blink-renderer-bindings-core-v8-v8_script_runner.cc.patch b/patches/third_party-blink-renderer-bindings-core-v8-v8_script_runner.cc.patch index 752a222b9242..2419cc9614c8 100644 --- a/patches/third_party-blink-renderer-bindings-core-v8-v8_script_runner.cc.patch +++ b/patches/third_party-blink-renderer-bindings-core-v8-v8_script_runner.cc.patch @@ -1,5 +1,5 @@ diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc -index 996c19fc0df15b5abfe3a4a2eceb9bc8a2f3da31..89c0c7e83a0dc1a96fe15f927f699aa87c68aeb6 100644 +index f9549008635e07d66a507c1db7d455f17d3551c9..2339bae5d48d93b9ea5387067439c4394caad038 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc @@ -218,7 +218,7 @@ int GetMicrotasksScopeDepth(v8::Isolate* isolate, diff --git a/patches/third_party-blink-renderer-bindings-generated_in_modules.gni.patch b/patches/third_party-blink-renderer-bindings-generated_in_modules.gni.patch index 618d9017204e..f06e948a0ac3 100644 --- a/patches/third_party-blink-renderer-bindings-generated_in_modules.gni.patch +++ b/patches/third_party-blink-renderer-bindings-generated_in_modules.gni.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni -index 3449b2d09007295513c10ef31a784c01e3d07f28..2be8e24aa9d3f0409ab09f4640bc8b640c0d681a 100644 +index f1916c51f3b1d516e3abc81f2260cea12f6fd6ea..6ea364349ee1dfabad22d8554e94327e46f213c5 100644 --- a/third_party/blink/renderer/bindings/generated_in_modules.gni +++ b/third_party/blink/renderer/bindings/generated_in_modules.gni -@@ -2822,6 +2822,7 @@ generated_interface_sources_in_modules = [ +@@ -2860,6 +2860,7 @@ generated_interface_sources_in_modules = [ "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_sub_image.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_webgl_sub_image.h", ] diff --git a/patches/third_party-blink-renderer-bindings-idl_in_modules.gni.patch b/patches/third_party-blink-renderer-bindings-idl_in_modules.gni.patch index 15025dc7b401..480bab107ed6 100644 --- a/patches/third_party-blink-renderer-bindings-idl_in_modules.gni.patch +++ b/patches/third_party-blink-renderer-bindings-idl_in_modules.gni.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni -index ac78d27520c8b54905a327eb1669937675e85b0f..a7699d0a44dd7cd4d5f0efc024da89495de9eb36 100644 +index 3f966143497fd1ce6c0b8ddae2fde7b2d47652ea..770327952357b180a4caa5a3e8aaec3196274013 100644 --- a/third_party/blink/renderer/bindings/idl_in_modules.gni +++ b/third_party/blink/renderer/bindings/idl_in_modules.gni -@@ -1210,6 +1210,7 @@ static_idl_files_in_modules = [ +@@ -1227,6 +1227,7 @@ static_idl_files_in_modules = [ "//third_party/blink/renderer/modules/xr/xr_webgl_layer_init.idl", "//third_party/blink/renderer/modules/xr/xr_webgl_sub_image.idl", ] diff --git a/patches/third_party-blink-renderer-bindings-scripts-bind_gen-interface.py.patch b/patches/third_party-blink-renderer-bindings-scripts-bind_gen-interface.py.patch index cc95a63645d8..6a1f483ee059 100644 --- a/patches/third_party-blink-renderer-bindings-scripts-bind_gen-interface.py.patch +++ b/patches/third_party-blink-renderer-bindings-scripts-bind_gen-interface.py.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py -index cfdef3a726650a9e800ae9315501358a81537e4a..3d18aacf5210341c016e1f4da938f6fe0b9edf70 100644 +index 80d594c125bd32f8cef2e22d4f5c0617460a9371..ac44d627a12f634b502a07801a47dd337250ec2b 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py -@@ -8314,3 +8314,4 @@ def generate_interfaces(task_queue): +@@ -7787,3 +7787,4 @@ def generate_interfaces(task_queue): "InitIDLInterfacesForTesting", "init_idl_interfaces_for_testing", for_testing=True) diff --git a/patches/third_party-blink-renderer-build-scripts-make_instrumenting_probes.py.patch b/patches/third_party-blink-renderer-build-scripts-make_instrumenting_probes.py.patch index f5a967c6ba15..0649fd61e139 100644 --- a/patches/third_party-blink-renderer-build-scripts-make_instrumenting_probes.py.patch +++ b/patches/third_party-blink-renderer-build-scripts-make_instrumenting_probes.py.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py -index f19596bf0adce1141f3e24a5f0e060c5a4a167a0..93bdd7d8ce58b8a66dcf16821cd570de81ed8932 100644 +index dc76ba59292e4052bf596dbc45caf07ee7661362..1054bbdca5b4e3400b999afdc82612cfe9522883 100644 --- a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py +++ b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py -@@ -306,5 +306,6 @@ def main(): +@@ -307,5 +307,6 @@ def main(): h_file.close() diff --git a/patches/third_party-blink-renderer-core-BUILD.gn.patch b/patches/third_party-blink-renderer-core-BUILD.gn.patch index 329e46b80fcd..841f1cae1bbd 100644 --- a/patches/third_party-blink-renderer-core-BUILD.gn.patch +++ b/patches/third_party-blink-renderer-core-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn -index 7b327be8a003ae01f79f71f00979ef0b2f45ac2a..2d8bee95575aabfcced665bbff548993ef2dfc1e 100644 +index d06b485aebb64def0f082b4f1627c7b69b91a29c..e983fa2d1082860e57f7d8e7eae61c4d7a595203 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn @@ -399,6 +399,7 @@ component("core") { diff --git a/patches/third_party-blink-renderer-core-dom-events-event_target.cc.patch b/patches/third_party-blink-renderer-core-dom-events-event_target.cc.patch index 756e300bd323..8efad4b8fa4f 100644 --- a/patches/third_party-blink-renderer-core-dom-events-event_target.cc.patch +++ b/patches/third_party-blink-renderer-core-dom-events-event_target.cc.patch @@ -1,5 +1,5 @@ diff --git a/third_party/blink/renderer/core/dom/events/event_target.cc b/third_party/blink/renderer/core/dom/events/event_target.cc -index 606a43d2b5493e3f81c82d0a2396cbf3d7b63319..430f8a43c9bf24a70169a66da0a72b0c3567b9f1 100644 +index b50afe96d2e2790ed91403c0a5bb143637cead76..224ba30a17ca1575a7c031a1d90dfe32c8044405 100644 --- a/third_party/blink/renderer/core/dom/events/event_target.cc +++ b/third_party/blink/renderer/core/dom/events/event_target.cc @@ -478,6 +478,7 @@ bool EventTarget::AddEventListenerInternal( @@ -10,7 +10,7 @@ index 606a43d2b5493e3f81c82d0a2396cbf3d7b63319..430f8a43c9bf24a70169a66da0a72b0c if (options->hasSignal()) { // Instead of passing the entire |options| here, which could create a // circular reference due to |options| holding a Member, just -@@ -638,6 +639,7 @@ bool EventTarget::RemoveEventListenerInternal( +@@ -640,6 +641,7 @@ bool EventTarget::RemoveEventListenerInternal( ®istered_listener)) { return false; } diff --git a/patches/third_party-blink-renderer-core-frame-dom_window.h.patch b/patches/third_party-blink-renderer-core-frame-dom_window.h.patch index b0f8c35093b6..8f437e7f0334 100644 --- a/patches/third_party-blink-renderer-core-frame-dom_window.h.patch +++ b/patches/third_party-blink-renderer-core-frame-dom_window.h.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/core/frame/dom_window.h b/third_party/blink/renderer/core/frame/dom_window.h -index 6e86def1fd4a3f69704e79fe2fb2f041f9aeb655..1d09f2733477722489fcdc64993f0a9182de6861 100644 +index 4787918edaf3495351c2e50d22f522d870eb7b58..6716ac810f34d16f269d48145361cea61cbcb677 100644 --- a/third_party/blink/renderer/core/frame/dom_window.h +++ b/third_party/blink/renderer/core/frame/dom_window.h -@@ -191,6 +191,7 @@ class CORE_EXPORT DOMWindow : public EventTarget { +@@ -193,6 +193,7 @@ class CORE_EXPORT DOMWindow : public EventTarget { void DisconnectFromFrame() { frame_ = nullptr; } diff --git a/patches/third_party-blink-renderer-core-html-canvas-canvas_async_blob_creator.cc.patch b/patches/third_party-blink-renderer-core-html-canvas-canvas_async_blob_creator.cc.patch index 08e19adc40c9..c95ec92b1566 100644 --- a/patches/third_party-blink-renderer-core-html-canvas-canvas_async_blob_creator.cc.patch +++ b/patches/third_party-blink-renderer-core-html-canvas-canvas_async_blob_creator.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc -index 72b4a15778f605209ff2ffd593277460c5a6a38a..5543294c041c430927f72d678cb2c8ac46ea5dd1 100644 +index 55a81b142ec864f4fd16be2dc5f9eea10687ab87..07e34ce26fd2aff861cd6282ebbf84488b3f5a02 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc -@@ -207,6 +207,7 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator( +@@ -209,6 +209,7 @@ CanvasAsyncBlobCreator::CanvasAsyncBlobCreator( src_data_.reset(info, src_data_.addr(), src_data_.rowBytes()); } } diff --git a/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.cc.patch b/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.cc.patch index 4abd460df913..38ecdde3a292 100644 --- a/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.cc.patch +++ b/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc -index 7d8a59ea6e0d3983711e305ce98e99abbe0bc06a..e87dba4ae082bfdd36514e01dece759a28ccc236 100644 +index 3a4a1fbcc1ef3a8b7e454076a0e6ce9efa775e9e..147cb250de2a92e91a94b14074c0b50b89080c57 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc -@@ -1169,6 +1169,7 @@ String HTMLCanvasElement::ToDataURLInternal( +@@ -1170,6 +1170,7 @@ String HTMLCanvasElement::ToDataURLInternal( if (!data_buffer) return String("data:,"); diff --git a/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.h.patch b/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.h.patch index 19fe75b4609b..9a427dc389a2 100644 --- a/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.h.patch +++ b/patches/third_party-blink-renderer-core-html-canvas-html_canvas_element.h.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h -index 521c600c02b9020c558d5542997f97d885282dc2..2b8fc87e11ced44575c56a5af18e887ff2f233ab 100644 +index fa8f2ded75f0c3de33afd11634aa8f0b5c80d3a1..87e56290ce925b7f1f0a914eafd013347c532296 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h -@@ -319,6 +319,7 @@ class CORE_EXPORT HTMLCanvasElement final +@@ -316,6 +316,7 @@ class CORE_EXPORT HTMLCanvasElement final bool ShouldDisableAccelerationBecauseOfReadback() const; diff --git a/patches/third_party-blink-renderer-core-permissions_policy-permissions_policy_features.json5.patch b/patches/third_party-blink-renderer-core-permissions_policy-permissions_policy_features.json5.patch index 1430c23508da..fbe25cc9974e 100644 --- a/patches/third_party-blink-renderer-core-permissions_policy-permissions_policy_features.json5.patch +++ b/patches/third_party-blink-renderer-core-permissions_policy-permissions_policy_features.json5.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 -index fb7b51e46e140953a9f9a52fd6c1c8d7509a96c3..546f6d5f8745c6f997c709f7e626f0266b0f394b 100644 +index 8066dafa639c5d6e6cc4b954b778de1e9ddf3c93..59f6b4f87b7845e0ca93a62fc5162a7d9c87ec98 100644 --- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 +++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_features.json5 -@@ -424,5 +424,13 @@ +@@ -428,5 +428,13 @@ // Parser also accepts "window-management" alias (crbug.com/1328581). permissions_policy_name: "window-placement", }, diff --git a/patches/third_party-blink-renderer-core-probe-BUILD.gn.patch b/patches/third_party-blink-renderer-core-probe-BUILD.gn.patch index b596023c0180..9f0ea3c7b29f 100644 --- a/patches/third_party-blink-renderer-core-probe-BUILD.gn.patch +++ b/patches/third_party-blink-renderer-core-probe-BUILD.gn.patch @@ -1,12 +1,12 @@ diff --git a/third_party/blink/renderer/core/probe/BUILD.gn b/third_party/blink/renderer/core/probe/BUILD.gn -index 064c19ed9d916359b52609aeeefe15297cd86b26..090b3da26c618750e355e59422cf74de0fa8f2bb 100644 +index 81e01c4d71515468d10a5f2e5e5a4b8cecca2279..236c147b87dd8495cb7282b9aec40a5976306bb6 100644 --- a/third_party/blink/renderer/core/probe/BUILD.gn +++ b/third_party/blink/renderer/core/probe/BUILD.gn -@@ -28,6 +28,7 @@ action("instrumentation_probes") { - "--output_dir", - rebase_path(blink_core_output_dir, root_build_dir), - ] -+ import("//brave/third_party/blink/renderer/core/probe/sources.gni") deps = brave_third_party_blink_renderer_core_probe_instrumentation_probes_deps +@@ -34,6 +34,7 @@ template("probe_generator") { + "--output_dir", + rebase_path(invoker.output, root_build_dir), + ] ++ import("//brave/third_party/blink/renderer/core/probe/sources.gni") deps = brave_third_party_blink_renderer_core_probe_instrumentation_probes_deps + } } - source_set("generated") { diff --git a/patches/third_party-blink-renderer-core-script-script_loader.cc.patch b/patches/third_party-blink-renderer-core-script-script_loader.cc.patch index 41ba46cc2311..b2b009508082 100644 --- a/patches/third_party-blink-renderer-core-script-script_loader.cc.patch +++ b/patches/third_party-blink-renderer-core-script-script_loader.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc -index 4540de053db6d2af0dd8394bc49057864c904b48..02fe66ff72044efeb2d312b81cbbc14896bdd45d 100644 +index 2e2ce4cbd72d6b6847d5b228531657f5a0b192ea..900b6458502858a7ca214a5088526a1cb3713b69 100644 --- a/third_party/blink/renderer/core/script/script_loader.cc +++ b/third_party/blink/renderer/core/script/script_loader.cc -@@ -714,6 +714,7 @@ PendingScript* ScriptLoader::PrepareScript( +@@ -727,6 +727,7 @@ PendingScript* ScriptLoader::PrepareScript( parser_state, credentials_mode, referrer_policy, fetch_priority_hint, render_blocking_behavior, RejectCoepUnsafeNone(false)); diff --git a/patches/third_party-blink-renderer-modules-BUILD.gn.patch b/patches/third_party-blink-renderer-modules-BUILD.gn.patch index f0bb40963f4f..7bd571ed3f02 100644 --- a/patches/third_party-blink-renderer-modules-BUILD.gn.patch +++ b/patches/third_party-blink-renderer-modules-BUILD.gn.patch @@ -1,5 +1,5 @@ diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn -index f586c6f41738ff6a3c126fff752066d0ff80ac30..cd9204d7966cd468fd6578de9f25aa844514e34b 100644 +index 55b20f0065a8ba84f40305592567397be4491fd5..d71052bf686536be516a570ef5a1cf7b4e936d65 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn @@ -19,6 +19,7 @@ if (is_ios) { @@ -10,7 +10,7 @@ index f586c6f41738ff6a3c126fff752066d0ff80ac30..cd9204d7966cd468fd6578de9f25aa84 config("modules_implementation") { defines = [ "BLINK_MODULES_IMPLEMENTATION=1" ] -@@ -173,6 +174,7 @@ component("modules") { +@@ -174,6 +175,7 @@ component("modules") { # generating the snapshot for android, blink is compiled with # current_os="linux" and target_os="android". Using target_os is necessary as # we need to compile in the same way as would happen when current_os="android". diff --git a/patches/third_party-blink-renderer-modules-canvas-canvas2d-base_rendering_context_2d.cc.patch b/patches/third_party-blink-renderer-modules-canvas-canvas2d-base_rendering_context_2d.cc.patch index 687acb968f59..2eb5648da21a 100644 --- a/patches/third_party-blink-renderer-modules-canvas-canvas2d-base_rendering_context_2d.cc.patch +++ b/patches/third_party-blink-renderer-modules-canvas-canvas2d-base_rendering_context_2d.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc -index 963a9d142316fa68675937dc8ca8d3f1927fec94..e8abd0b46c586e1053039291cccacf3cd782db2f 100644 +index f09459b0b67c37d307c70a516731d05db49f49b8..83cbc9acdb3810fc6bc59d1b14d32fc3d25624ce 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc -@@ -2044,6 +2044,7 @@ ImageData* BaseRenderingContext2D::getImageData( +@@ -2047,6 +2047,7 @@ ImageData* BaseRenderingContext2D::getImageData( } ImageData* BaseRenderingContext2D::getImageDataInternal( @@ -10,7 +10,7 @@ index 963a9d142316fa68675937dc8ca8d3f1927fec94..e8abd0b46c586e1053039291cccacf3c int sx, int sy, int sw, -@@ -2186,6 +2187,7 @@ ImageData* BaseRenderingContext2D::getImageDataInternal( +@@ -2189,6 +2190,7 @@ ImageData* BaseRenderingContext2D::getImageDataInternal( DCHECK(!bounds.intersect(SkIRect::MakeXYWH(sx, sy, sw, sh))); } } @@ -18,3 +18,11 @@ index 963a9d142316fa68675937dc8ca8d3f1927fec94..e8abd0b46c586e1053039291cccacf3c return image_data; } +@@ -2858,6 +2860,7 @@ TextMetrics* BaseRenderingContext2D::measureText(const String& text) { + return MakeGarbageCollected(); + } + ++ BRAVE_BASE_RENDERING_CONTEXT_2D_MEASURE_TEXT + canvas->GetDocument().UpdateStyleAndLayoutTreeForNode( + canvas, DocumentUpdateReason::kCanvas); + } diff --git a/patches/third_party-blink-renderer-modules-canvas-canvas2d-canvas_rendering_context_2d.cc.patch b/patches/third_party-blink-renderer-modules-canvas-canvas2d-canvas_rendering_context_2d.cc.patch deleted file mode 100644 index 767ef63aeb11..000000000000 --- a/patches/third_party-blink-renderer-modules-canvas-canvas2d-canvas_rendering_context_2d.cc.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc -index a48dc6092ef6e50984faf6da698d117cb1005cbf..d4ec5e96ab4788d43f18c02aa882b68b5b11aee6 100644 ---- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc -+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc -@@ -916,6 +916,7 @@ TextMetrics* CanvasRenderingContext2D::measureText(const String& text) { - if (!canvas()->GetDocument().GetFrame()) - return MakeGarbageCollected(); - -+ BRAVE_CANVAS_RENDERING_CONTEXT_2D_MEASURE_TEXT - canvas()->GetDocument().UpdateStyleAndLayoutTreeForNode( - canvas(), DocumentUpdateReason::kCanvas); - diff --git a/patches/third_party-blink-renderer-modules-mediastream-media_devices.cc.patch b/patches/third_party-blink-renderer-modules-mediastream-media_devices.cc.patch index 3286953f82fc..e02e6cb0e58a 100644 --- a/patches/third_party-blink-renderer-modules-mediastream-media_devices.cc.patch +++ b/patches/third_party-blink-renderer-modules-mediastream-media_devices.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc -index 0fcf8943a65cf971a61068bf26770fc3ceb2ba13..d6fcfa04537f6fd13cae181e786ea31167b0e9be 100644 +index 963bfe70c3a53e7e5e72b300da1e60b8f0f0d403..0938f2d5460b3c6ce01d3240eeefe2feb39e1bf4 100644 --- a/third_party/blink/renderer/modules/mediastream/media_devices.cc +++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc -@@ -1002,6 +1002,7 @@ void MediaDevices::DevicesEnumerated( +@@ -1005,6 +1005,7 @@ void MediaDevices::DevicesEnumerated( } } diff --git a/patches/third_party-blink-renderer-modules-webaudio-analyser_handler.cc.patch b/patches/third_party-blink-renderer-modules-webaudio-analyser_handler.cc.patch index d9a80ebc0424..0ad90f0b9cdd 100644 --- a/patches/third_party-blink-renderer-modules-webaudio-analyser_handler.cc.patch +++ b/patches/third_party-blink-renderer-modules-webaudio-analyser_handler.cc.patch @@ -1,12 +1,12 @@ diff --git a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc -index a3ef095cdeba50edc14b278cfc802a306e2719e8..b0a1a44add7d0cd3dae13ecbff6664831d8f608a 100644 +index b2f3242426930b06694a12296206da1e7a7abfb7..9f523172e49757ac1f5524c6bbe8b814bf41c40f 100644 --- a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc @@ -23,6 +23,7 @@ AnalyserHandler::AnalyserHandler(AudioNode& node, float sample_rate) - : AudioBasicInspectorHandler(kNodeTypeAnalyser, node, sample_rate), + : AudioHandler(kNodeTypeAnalyser, node, sample_rate), analyser_( node.context()->GetDeferredTaskHandler().RenderQuantumFrames()) { + BRAVE_ANALYSERHANDLER_CONSTRUCTOR + AddInput(); channel_count_ = kDefaultNumberOfInputChannels; AddOutput(kDefaultNumberOfOutputChannels); - diff --git a/patches/third_party-blink-renderer-modules-webgl-webgl2_rendering_context_base.cc.patch b/patches/third_party-blink-renderer-modules-webgl-webgl2_rendering_context_base.cc.patch index 1b94cece11f2..091a27a326c9 100644 --- a/patches/third_party-blink-renderer-modules-webgl-webgl2_rendering_context_base.cc.patch +++ b/patches/third_party-blink-renderer-modules-webgl-webgl2_rendering_context_base.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc -index 0933654f42a6a367d9a9f03100d25861469ec29a..0a63dc25b998ee21ec04e5998d0baf451193a0fc 100644 +index 8b1406045b66fa6c187f6d88f2f48b2343329cd9..1278e08f2ef66d19b04f79858957c03eaefb5787 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc -@@ -5259,6 +5259,7 @@ ScriptValue WebGL2RenderingContextBase::getParameter(ScriptState* script_state, +@@ -5299,6 +5299,7 @@ ScriptValue WebGL2RenderingContextBase::getParameter(ScriptState* script_state, GLenum pname) { if (isContextLost()) return ScriptValue::CreateNull(script_state->GetIsolate()); @@ -10,7 +10,7 @@ index 0933654f42a6a367d9a9f03100d25861469ec29a..0a63dc25b998ee21ec04e5998d0baf45 switch (pname) { case GL_SHADING_LANGUAGE_VERSION: { return WebGLAny( -@@ -5858,6 +5859,7 @@ ScriptValue WebGL2RenderingContextBase::getFramebufferAttachmentParameter( +@@ -5911,6 +5912,7 @@ ScriptValue WebGL2RenderingContextBase::getFramebufferAttachmentParameter( if (isContextLost() || !ValidateGetFramebufferAttachmentParameterFunc( kFunctionName, target, attachment)) return ScriptValue::CreateNull(script_state->GetIsolate()); @@ -18,7 +18,7 @@ index 0933654f42a6a367d9a9f03100d25861469ec29a..0a63dc25b998ee21ec04e5998d0baf45 WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target); DCHECK(!framebuffer_binding || framebuffer_binding->Object()); -@@ -6076,6 +6078,7 @@ ScriptValue WebGL2RenderingContextBase::getTexParameter( +@@ -6129,6 +6131,7 @@ ScriptValue WebGL2RenderingContextBase::getTexParameter( GLenum pname) { if (isContextLost() || !ValidateTextureBinding("getTexParameter", target)) return ScriptValue::CreateNull(script_state->GetIsolate()); diff --git a/patches/third_party-blink-renderer-modules-webgl-webgl_rendering_context_base.cc.patch b/patches/third_party-blink-renderer-modules-webgl-webgl_rendering_context_base.cc.patch index b31559b29543..37ae7e925e39 100644 --- a/patches/third_party-blink-renderer-modules-webgl-webgl_rendering_context_base.cc.patch +++ b/patches/third_party-blink-renderer-modules-webgl-webgl_rendering_context_base.cc.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc -index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d16f57c51 100644 +index be97bf6e0a41f48d7fecce491a2324f2c7655852..69ebda6132fb20b6aa76cf27d73e41346b8bc67a 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc -@@ -3170,6 +3170,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib( +@@ -3169,6 +3169,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib( GLuint index) { if (!ValidateWebGLProgramOrShader("getActiveAttrib", program)) return nullptr; @@ -10,7 +10,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d GLuint program_id = ObjectNonZero(program); GLint max_name_length = -1; ContextGL()->GetProgramiv(program_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, -@@ -3201,6 +3202,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform( +@@ -3200,6 +3201,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform( GLuint index) { if (!ValidateWebGLProgramOrShader("getActiveUniform", program)) return nullptr; @@ -18,7 +18,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d GLuint program_id = ObjectNonZero(program); GLint max_name_length = -1; ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, -@@ -3231,6 +3233,7 @@ absl::optional>> +@@ -3230,6 +3232,7 @@ absl::optional>> WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program) { if (!ValidateWebGLProgramOrShader("getAttachedShaders", program)) return absl::nullopt; @@ -26,7 +26,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d HeapVector> shader_objects; for (GLenum shaderType : {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER}) { -@@ -3245,6 +3248,7 @@ GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, +@@ -3244,6 +3247,7 @@ GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name) { if (!ValidateWebGLProgramOrShader("getAttribLocation", program)) return -1; @@ -34,7 +34,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (!ValidateLocationLength("getAttribLocation", name)) return -1; if (!ValidateString("getAttribLocation", name)) -@@ -3278,6 +3282,7 @@ ScriptValue WebGLRenderingContextBase::getBufferParameter( +@@ -3277,6 +3281,7 @@ ScriptValue WebGLRenderingContextBase::getBufferParameter( GLenum pname) { if (isContextLost() || !ValidateBufferTarget("getBufferParameter", target)) return ScriptValue::CreateNull(script_state->GetIsolate()); @@ -42,7 +42,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d switch (pname) { case GL_BUFFER_USAGE: { -@@ -3418,6 +3423,7 @@ ScriptValue WebGLRenderingContextBase::getFramebufferAttachmentParameter( +@@ -3417,6 +3422,7 @@ ScriptValue WebGLRenderingContextBase::getFramebufferAttachmentParameter( return ScriptValue::CreateNull(script_state->GetIsolate()); } @@ -50,7 +50,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (!framebuffer_binding_ || !framebuffer_binding_->Object()) { SynthesizeGLError(GL_INVALID_OPERATION, kFunctionName, "no framebuffer bound"); -@@ -3814,6 +3820,7 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state, +@@ -3813,6 +3819,7 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state, "invalid parameter name, OES_standard_derivatives not enabled"); return ScriptValue::CreateNull(script_state->GetIsolate()); case WebGLDebugRendererInfo::kUnmaskedRendererWebgl: @@ -58,7 +58,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (ExtensionEnabled(kWebGLDebugRendererInfoName)) { if (IdentifiabilityStudySettings::Get()->ShouldSampleType( blink::IdentifiableSurface::Type::kWebGLParameter)) { -@@ -3829,6 +3836,7 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state, +@@ -3828,6 +3835,7 @@ ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state, "invalid parameter name, WEBGL_debug_renderer_info not enabled"); return ScriptValue::CreateNull(script_state->GetIsolate()); case WebGLDebugRendererInfo::kUnmaskedVendorWebgl: @@ -66,7 +66,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (ExtensionEnabled(kWebGLDebugRendererInfoName)) { if (IdentifiabilityStudySettings::Get()->ShouldSampleType( blink::IdentifiableSurface::Type::kWebGLParameter)) { -@@ -3921,6 +3929,7 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter( +@@ -3955,6 +3963,7 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter( // intended to prevent applications from entering an infinite polling loop. if (isContextLost() && pname == GL_COMPLETION_STATUS_KHR) return WebGLAny(script_state, true); @@ -74,7 +74,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (!ValidateWebGLProgramOrShader("getProgramParamter", program)) { return ScriptValue::CreateNull(script_state->GetIsolate()); } -@@ -3976,6 +3985,7 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter( +@@ -4010,6 +4019,7 @@ ScriptValue WebGLRenderingContextBase::getProgramParameter( String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program) { if (!ValidateWebGLProgramOrShader("getProgramInfoLog", program)) return String(); @@ -82,7 +82,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d GLStringQuery query(ContextGL()); return query.Run(ObjectNonZero(program)); } -@@ -3986,6 +3996,7 @@ ScriptValue WebGLRenderingContextBase::getRenderbufferParameter( +@@ -4020,6 +4030,7 @@ ScriptValue WebGLRenderingContextBase::getRenderbufferParameter( GLenum pname) { if (isContextLost()) return ScriptValue::CreateNull(script_state->GetIsolate()); @@ -90,7 +90,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (target != GL_RENDERBUFFER) { SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter", "invalid target"); -@@ -4037,6 +4048,7 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter( +@@ -4071,6 +4082,7 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter( // intended to prevent applications from entering an infinite polling loop. if (isContextLost() && pname == GL_COMPLETION_STATUS_KHR) return WebGLAny(script_state, true); @@ -98,7 +98,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (!ValidateWebGLProgramOrShader("getShaderParameter", shader)) { return ScriptValue::CreateNull(script_state->GetIsolate()); } -@@ -4068,6 +4080,7 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter( +@@ -4102,6 +4114,7 @@ ScriptValue WebGLRenderingContextBase::getShaderParameter( String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader) { if (!ValidateWebGLProgramOrShader("getShaderInfoLog", shader)) return String(); @@ -106,7 +106,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d GLStringQuery query(ContextGL()); return query.Run(ObjectNonZero(shader)); } -@@ -4098,6 +4111,7 @@ WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat( +@@ -4132,6 +4145,7 @@ WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat( GLint precision = 0; ContextGL()->GetShaderPrecisionFormat(shader_type, precision_type, range, &precision); @@ -114,7 +114,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d auto* result = MakeGarbageCollected( range[0], range[1], precision); if (IdentifiabilityStudySettings::Get()->ShouldSampleType( -@@ -4110,6 +4124,7 @@ WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat( +@@ -4144,6 +4158,7 @@ WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat( String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) { if (!ValidateWebGLProgramOrShader("getShaderSource", shader)) return String(); @@ -122,7 +122,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d return EnsureNotNull(shader->Source()); } -@@ -4135,6 +4150,7 @@ ScriptValue WebGLRenderingContextBase::getTexParameter( +@@ -4169,6 +4184,7 @@ ScriptValue WebGLRenderingContextBase::getTexParameter( GLenum pname) { if (isContextLost()) return ScriptValue::CreateNull(script_state->GetIsolate()); @@ -130,7 +130,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (!ValidateTextureBinding("getTexParameter", target)) return ScriptValue::CreateNull(script_state->GetIsolate()); switch (pname) { -@@ -4169,6 +4185,7 @@ ScriptValue WebGLRenderingContextBase::getUniform( +@@ -4203,6 +4219,7 @@ ScriptValue WebGLRenderingContextBase::getUniform( const WebGLUniformLocation* uniform_location) { if (!ValidateWebGLProgramOrShader("getUniform", program)) return ScriptValue::CreateNull(script_state->GetIsolate()); @@ -138,7 +138,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d DCHECK(uniform_location); if (uniform_location->Program() != program) { SynthesizeGLError(GL_INVALID_OPERATION, "getUniform", -@@ -4428,6 +4445,7 @@ WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation( +@@ -4462,6 +4479,7 @@ WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation( const String& name) { if (!ValidateWebGLProgramOrShader("getUniformLocation", program)) return nullptr; @@ -146,7 +146,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (!ValidateLocationLength("getUniformLocation", name)) return nullptr; if (!ValidateString("getUniformLocation", name)) -@@ -4452,6 +4470,7 @@ ScriptValue WebGLRenderingContextBase::getVertexAttrib( +@@ -4486,6 +4504,7 @@ ScriptValue WebGLRenderingContextBase::getVertexAttrib( GLenum pname) { if (isContextLost()) return ScriptValue::CreateNull(script_state->GetIsolate()); @@ -154,7 +154,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d if (index >= max_vertex_attribs_) { SynthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib", "index out of range"); -@@ -4529,6 +4548,7 @@ int64_t WebGLRenderingContextBase::getVertexAttribOffset(GLuint index, +@@ -4563,6 +4582,7 @@ int64_t WebGLRenderingContextBase::getVertexAttribOffset(GLuint index, GLenum pname) { if (isContextLost()) return 0; @@ -162,7 +162,7 @@ index 74a289a88a95318a6a1020e762b2adc1aa79911f..8d1ac8b185332f98dcadc0bf9fe90f3d GLvoid* result = nullptr; // NOTE: If pname is ever a value that returns more than 1 element // this will corrupt memory. -@@ -4888,6 +4908,7 @@ void WebGLRenderingContextBase::ReadPixelsHelper(GLint x, +@@ -4922,6 +4942,7 @@ void WebGLRenderingContextBase::ReadPixelsHelper(GLint x, int64_t offset) { if (isContextLost()) return; diff --git a/patches/third_party-blink-renderer-platform-BUILD.gn.patch b/patches/third_party-blink-renderer-platform-BUILD.gn.patch index 450ac6d30022..5f06c95b539b 100644 --- a/patches/third_party-blink-renderer-platform-BUILD.gn.patch +++ b/patches/third_party-blink-renderer-platform-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn -index 92b45cb4939df8fc71802a6828543cedf2a73664..384ca9e38c5ddab5991a4bbdbd9d87f7920e54c9 100644 +index 5ecdd70e2152ac90159cd98a7fb20a5128931ca0..ef4df9103c75b59669f96410ab3f81fe0e996f51 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn -@@ -1841,6 +1841,7 @@ component("platform") { +@@ -1849,6 +1849,7 @@ component("platform") { configs -= [ "//build/config/compiler:default_symbols" ] configs += blink_symbols_config diff --git a/patches/third_party-rust-winapi-v0_3-BUILD.gn.patch b/patches/third_party-rust-winapi-v0_3-BUILD.gn.patch index 8e5add8e6ef7..c0d93aa50de8 100644 --- a/patches/third_party-rust-winapi-v0_3-BUILD.gn.patch +++ b/patches/third_party-rust-winapi-v0_3-BUILD.gn.patch @@ -1,10 +1,10 @@ diff --git a/third_party/rust/winapi/v0_3/BUILD.gn b/third_party/rust/winapi/v0_3/BUILD.gn -index 95af7eea1cd47086ebabaac7ab42a6305d4e70b0..87c3ada4a20dde6c2e0a0dad0372b30c7a3b6087 100644 +index bf081cdef85dd1c05d8f016d991cff963112de37..2c1b8df701f526bfab8d325f139197b6dc1f426f 100644 --- a/third_party/rust/winapi/v0_3/BUILD.gn +++ b/third_party/rust/winapi/v0_3/BUILD.gn -@@ -452,4 +452,5 @@ cargo_crate("lib") { +@@ -450,4 +450,5 @@ cargo_crate("lib") { ] build_root = "crate/build.rs" build_sources = [ "crate/build.rs" ] -+ features += [ "basetsd", "cfg", "cfgmgr32", "devpropdef", "excpt", "ktmtypes", "libloaderapi", "limits", "ntdef", "ntstatus", "processthreadsapi", "reason", "rpcndr", "timezoneapi", "vadefs", "vcruntime", "wincontypes", "wingdi", "windef", "winreg", "winuser", "wtypesbase" ] ++ features += [ "basetsd", "cfg", "cfgmgr32", "devpropdef", "excpt", "handleapi", "ktmtypes", "libloaderapi", "limits", "ntdef", "ntstatus", "processthreadsapi", "reason", "rpcndr", "timezoneapi", "vadefs", "vcruntime", "wincontypes", "wingdi", "windef", "winreg", "winuser", "wtypesbase" ] } diff --git a/patches/third_party/devtools-frontend/src/front_end-panels-application-ApplicationPanelSidebar.ts.patch b/patches/third_party/devtools-frontend/src/front_end-panels-application-ApplicationPanelSidebar.ts.patch index 3f7dee0389e1..d80e1973d242 100644 --- a/patches/third_party/devtools-frontend/src/front_end-panels-application-ApplicationPanelSidebar.ts.patch +++ b/patches/third_party/devtools-frontend/src/front_end-panels-application-ApplicationPanelSidebar.ts.patch @@ -1,8 +1,8 @@ diff --git a/front_end/panels/application/ApplicationPanelSidebar.ts b/front_end/panels/application/ApplicationPanelSidebar.ts -index b161036288c86f1e582dda55305ab13db3c5d484..d606a6a385920e6e4d85787671146e330ff6e0a4 100644 +index ab4b086f80a2efba3b5ac7edf2d1d6e70394339a..29e0ef9da7ce781e9cb8b4d4e4af858ae3e6fa93 100644 --- a/front_end/panels/application/ApplicationPanelSidebar.ts +++ b/front_end/panels/application/ApplicationPanelSidebar.ts -@@ -489,6 +489,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe +@@ -483,6 +483,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe // Work-around for crbug.com/1152713: Something is wrong with custom scrollbars and size containment. // @ts-ignore this.contentElement.style.contain = 'layout style'; diff --git a/patches/tools-gritsettings-resource_ids.spec.patch b/patches/tools-gritsettings-resource_ids.spec.patch index 5e76e7a7cf4b..52dc5f77c9e3 100644 --- a/patches/tools-gritsettings-resource_ids.spec.patch +++ b/patches/tools-gritsettings-resource_ids.spec.patch @@ -1,5 +1,5 @@ diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec -index a327136986b82869f394f47e4609e431c9f3a3ac..d319efc39086c0efc76d6babc78263527edca349 100644 +index e65fe348a1b7eaed2871cc811cb8c7a40dc9f92b..b1240acd93b5a8946e2aeff33b3f1151dc203ef3 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec @@ -38,6 +38,9 @@ @@ -12,7 +12,7 @@ index a327136986b82869f394f47e4609e431c9f3a3ac..d319efc39086c0efc76d6babc7826352 "chrome/app/google_chrome_strings.grd": { "messages": [800], }, -@@ -252,7 +255,7 @@ +@@ -260,7 +263,7 @@ "includes": [3060], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/history/resources.grd": { @@ -21,7 +21,7 @@ index a327136986b82869f394f47e4609e431c9f3a3ac..d319efc39086c0efc76d6babc7826352 "includes": [3080], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/identity_internals/resources.grd": { -@@ -383,7 +386,7 @@ +@@ -391,7 +394,7 @@ "includes": [3710], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/settings/resources.grd": { @@ -30,7 +30,7 @@ index a327136986b82869f394f47e4609e431c9f3a3ac..d319efc39086c0efc76d6babc7826352 "includes": [3720], }, "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/settings_shared/resources.grd": { -@@ -868,6 +871,9 @@ +@@ -884,6 +887,9 @@ "components/components_chromium_strings.grd": { "messages": [6020], }, diff --git a/patches/tools-licenses-licenses.py.patch b/patches/tools-licenses-licenses.py.patch index 9a9413c45bb0..803f378e0292 100644 --- a/patches/tools-licenses-licenses.py.patch +++ b/patches/tools-licenses-licenses.py.patch @@ -1,8 +1,8 @@ diff --git a/tools/licenses/licenses.py b/tools/licenses/licenses.py -index 15b461326e2ce4bd255cbe779b449261a7f63f09..4ad542a3e8d1b806f7e63b7c10a4d37cd9b56b0a 100755 +index 9a34155c5066b5e8c08c205170d48afb0f4caa92..1c5e2677689ff823b2618236a769238fd98d4dc8 100755 --- a/tools/licenses/licenses.py +++ b/tools/licenses/licenses.py -@@ -39,6 +39,7 @@ _REPOSITORY_ROOT = os.path.abspath( +@@ -41,6 +41,7 @@ _REPOSITORY_ROOT = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..')) sys.path.insert(0, os.path.join(_REPOSITORY_ROOT, 'build')) import action_helpers @@ -10,7 +10,7 @@ index 15b461326e2ce4bd255cbe779b449261a7f63f09..4ad542a3e8d1b806f7e63b7c10a4d37c # Paths from the root of the tree to directories to skip. PRUNE_PATHS = set([ -@@ -425,6 +426,7 @@ SPECIAL_CASES = { +@@ -426,6 +427,7 @@ SPECIAL_CASES = { "License File": ["//third_party/selenium-atoms/LICENSE.closure"], }, } @@ -18,7 +18,7 @@ index 15b461326e2ce4bd255cbe779b449261a7f63f09..4ad542a3e8d1b806f7e63b7c10a4d37c # These buildtools/third_party directories only contain # chromium build files. The actual third_party source files and their -@@ -708,7 +710,8 @@ def FindThirdPartyDirs(prune_paths, root, extra_third_party_dirs=None): +@@ -710,7 +712,8 @@ def FindThirdPartyDirs(prune_paths, root, extra_third_party_dirs=None): if skip in dirs: dirs.remove(skip) @@ -28,7 +28,7 @@ index 15b461326e2ce4bd255cbe779b449261a7f63f09..4ad542a3e8d1b806f7e63b7c10a4d37c # Add all subdirectories that are not marked for skipping. for dir in dirs: dirpath = os.path.join(path, dir) -@@ -956,7 +959,8 @@ def GenerateCredits(file_template_file, +@@ -959,7 +962,8 @@ def GenerateCredits(file_template_file, enable_warnings=enable_warnings) if not metadata: continue diff --git a/patches/tools-metrics-histograms-metadata-histogram_suffixes_list.xml.patch b/patches/tools-metrics-histograms-metadata-histogram_suffixes_list.xml.patch index 03836a75e5ad..bc9484a37ac1 100644 --- a/patches/tools-metrics-histograms-metadata-histogram_suffixes_list.xml.patch +++ b/patches/tools-metrics-histograms-metadata-histogram_suffixes_list.xml.patch @@ -1,8 +1,8 @@ diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml -index 910c79ec77ee34d427b1ba912cc8443d4c274c3c..723238c1a29bc27c85e95129116968877b16d3da 100644 +index f5d80ee2fe271abda05ffaad457702ee795deee5..2835548d1e9be1dd48bd391da64f4da2aa24b564 100644 --- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml -@@ -3458,6 +3458,7 @@ chromium-metrics-reviews@google.com. +@@ -3467,6 +3467,7 @@ chromium-metrics-reviews@google.com. diff --git a/patches/ui-accessibility-platform-ax_platform_node_cocoa.mm.patch b/patches/ui-accessibility-platform-ax_platform_node_cocoa.mm.patch index dc72a374548c..e31506e568c5 100644 --- a/patches/ui-accessibility-platform-ax_platform_node_cocoa.mm.patch +++ b/patches/ui-accessibility-platform-ax_platform_node_cocoa.mm.patch @@ -1,8 +1,8 @@ diff --git a/ui/accessibility/platform/ax_platform_node_cocoa.mm b/ui/accessibility/platform/ax_platform_node_cocoa.mm -index 5b73bea06e2d038e674bf44927a6015b18ff1f41..d379d1c61b991818da43966d48aa0fbe7456c958 100644 +index 62291c7edd6cbd26e8040a633509eea1605c4ebf..598f32a00ed35741973915d1bd6d7743f465a007 100644 --- a/ui/accessibility/platform/ax_platform_node_cocoa.mm +++ b/ui/accessibility/platform/ax_platform_node_cocoa.mm -@@ -2576,6 +2576,7 @@ void CollectAncestorRoles( +@@ -2586,6 +2586,7 @@ void CollectAncestorRoles( if (!_node) return nil; diff --git a/patches/ui-native_theme-native_theme_win.cc.patch b/patches/ui-native_theme-native_theme_win.cc.patch index 9f7c1aeae8ed..adcefb092b8f 100644 --- a/patches/ui-native_theme-native_theme_win.cc.patch +++ b/patches/ui-native_theme-native_theme_win.cc.patch @@ -1,8 +1,8 @@ diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc -index d3f9fcbed28f92a113fc2734cc0789e663ccfff9..ab8b87aa3ea25f49ef2f970e5a21bf621e658836 100644 +index 595b7185832126dd3d8ca85c445b835e5969adcb..fcc7d08dc1cf25944ed93ff22363a9e3b4f32641 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc -@@ -1597,6 +1597,7 @@ void NativeThemeWin::UpdateDarkModeStatus() { +@@ -1664,6 +1664,7 @@ void NativeThemeWin::UpdateDarkModeStatus() { &apps_use_light_theme); dark_mode_enabled = (apps_use_light_theme == 0); } diff --git a/patches/ui-native_theme-native_theme_win.h.patch b/patches/ui-native_theme-native_theme_win.h.patch index 85f44ddfb0fe..f5d1c459f4e9 100644 --- a/patches/ui-native_theme-native_theme_win.h.patch +++ b/patches/ui-native_theme-native_theme_win.h.patch @@ -1,5 +1,5 @@ diff --git a/ui/native_theme/native_theme_win.h b/ui/native_theme/native_theme_win.h -index ea47878d12046bca8ceb01bc8459de77a6402a44..2a574a60ba72d23d1b85d0b52a394eedcf10c1cb 100644 +index ed2d981b787b225c69c651fc1a68c9a7facca167..7a8b17a0d0a6a47dee234eab67f76b239aa2eccc 100644 --- a/ui/native_theme/native_theme_win.h +++ b/ui/native_theme/native_theme_win.h @@ -76,6 +76,7 @@ class NATIVE_THEME_EXPORT NativeThemeWin : public NativeTheme, diff --git a/patches/ui-views-controls-menu-menu_separator.cc.patch b/patches/ui-views-controls-menu-menu_separator.cc.patch index 2577912c9a5d..1b60739a4bb8 100644 --- a/patches/ui-views-controls-menu-menu_separator.cc.patch +++ b/patches/ui-views-controls-menu-menu_separator.cc.patch @@ -1,8 +1,8 @@ diff --git a/ui/views/controls/menu/menu_separator.cc b/ui/views/controls/menu/menu_separator.cc -index 19a1d9cd66600daf055e04fd573021fab7adf81e..ac624b11a035b938d3e8c3acefba66da570d523d 100644 +index 33c0089c2d85f50c460734beb4779051204287fe..acdfc87245105ea75b8b5c612222a4430286a98d 100644 --- a/ui/views/controls/menu/menu_separator.cc +++ b/ui/views/controls/menu/menu_separator.cc -@@ -48,6 +48,7 @@ void MenuSeparator::OnPaint(gfx::Canvas* canvas) { +@@ -49,6 +49,7 @@ void MenuSeparator::OnPaint(gfx::Canvas* canvas) { menu_config.separator_horizontal_border_padding, y, width() - menu_config.separator_horizontal_border_padding * 2, separator_thickness); diff --git a/patches/ui-webui-resources-cr_elements-BUILD.gn.patch b/patches/ui-webui-resources-cr_elements-BUILD.gn.patch index 6a61df974310..0a2c0a291c91 100644 --- a/patches/ui-webui-resources-cr_elements-BUILD.gn.patch +++ b/patches/ui-webui-resources-cr_elements-BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn -index bee4d3cdd662960eb4e01cf58243d7c34945d455..2eeb00ff4bdbf252f1ccfe9d77bd564d8d198923 100644 +index 0437abb35c5aded7700cdb6ad90f8d4a95df0187..b40a900a2bc0c787ef26ba38ac67840555af6eb9 100644 --- a/ui/webui/resources/cr_elements/BUILD.gn +++ b/ui/webui/resources/cr_elements/BUILD.gn -@@ -63,6 +63,7 @@ build_webui("build") { +@@ -64,6 +64,7 @@ build_webui("build") { web_component_files += [ "cr_searchable_drop_down/cr_searchable_drop_down.ts" ] } diff --git a/patches/ui-webui-resources-cr_elements-cr_shared_vars.css.patch b/patches/ui-webui-resources-cr_elements-cr_shared_vars.css.patch index 57731a525a68..921bd259e8fb 100644 --- a/patches/ui-webui-resources-cr_elements-cr_shared_vars.css.patch +++ b/patches/ui-webui-resources-cr_elements-cr_shared_vars.css.patch @@ -1,5 +1,5 @@ diff --git a/ui/webui/resources/cr_elements/cr_shared_vars.css b/ui/webui/resources/cr_elements/cr_shared_vars.css -index 84997fba2cecac4e296abdb5be6a79ec15118fc0..41155a924dcd98e97cc0320f57c5bc2a77178c8b 100644 +index c4ad462feb42871f029a696b515a1ecdcc2ea993..c7f6cd9049902cd05f7dc2aca8b75150212817ca 100644 --- a/ui/webui/resources/cr_elements/cr_shared_vars.css +++ b/ui/webui/resources/cr_elements/cr_shared_vars.css @@ -5,6 +5,7 @@ diff --git a/patches/v8/BUILD.gn.patch b/patches/v8/BUILD.gn.patch index 88b8b4e16335..ad2973df7af1 100644 --- a/patches/v8/BUILD.gn.patch +++ b/patches/v8/BUILD.gn.patch @@ -1,8 +1,8 @@ diff --git a/BUILD.gn b/BUILD.gn -index ca081a790959d22b12f10e9c08f9acbc339e7ed7..75e8633e06650893a6be06e1edd2753360602fcf 100644 +index dd97c4f922c81a65bdc401e251612333ca63ee78..95a848560ceb9f2d74e95c7e35603c02871417f2 100644 --- a/BUILD.gn +++ b/BUILD.gn -@@ -724,6 +724,7 @@ config("internal_config_base") { +@@ -732,6 +732,7 @@ config("internal_config_base") { "$target_gen_dir", "$target_gen_dir/include", ] @@ -10,7 +10,7 @@ index ca081a790959d22b12f10e9c08f9acbc339e7ed7..75e8633e06650893a6be06e1edd27533 } config("internal_config") { -@@ -2974,6 +2975,7 @@ v8_header_set("v8_headers") { +@@ -2999,6 +3000,7 @@ v8_header_set("v8_headers") { ":cppgc_headers", ":v8_version", ] diff --git a/patches/v8/src-codegen-compiler.cc.patch b/patches/v8/src-codegen-compiler.cc.patch index 69bce2002744..c28c3baa35e8 100644 --- a/patches/v8/src-codegen-compiler.cc.patch +++ b/patches/v8/src-codegen-compiler.cc.patch @@ -1,8 +1,8 @@ diff --git a/src/codegen/compiler.cc b/src/codegen/compiler.cc -index 8de7d7398bb01475ff58c1575e6cfb4823e3e836..5d36d8c3590beb2475ef281502705b86e7de53b5 100644 +index 972898e2a95e59c036cb8a284859cb81b5f6af71..70384ae5d9c39f2b6a9e419fa68d54f5d8a5d0e3 100644 --- a/src/codegen/compiler.cc +++ b/src/codegen/compiler.cc -@@ -2954,6 +2954,7 @@ MaybeHandle Compiler::GetFunctionFromEval( +@@ -2961,6 +2961,7 @@ MaybeHandle Compiler::GetFunctionFromEval( } } DCHECK(is_compiled_scope.is_compiled()); diff --git a/resources/resource_ids.spec b/resources/resource_ids.spec index 1ef5357c361d..eeabe223f256 100644 --- a/resources/resource_ids.spec +++ b/resources/resource_ids.spec @@ -4,10 +4,10 @@ { "SRCDIR": "../..", "brave/common/extensions/api/brave_api_resources.grd": { - "includes": [50800], + "includes": [50700], }, "brave/components/resources/brave_components_resources.grd": { - "includes": [50810], + "includes": [50710], }, # This file is generated during the build. "<(SHARED_INTERMEDIATE_DIR)/brave/web-ui-brave_adblock/brave_adblock.grd": { diff --git a/script/chromium-rebase-l10n.py b/script/chromium-rebase-l10n.py index e5c381274399..2e044a473b76 100755 --- a/script/chromium-rebase-l10n.py +++ b/script/chromium-rebase-l10n.py @@ -257,6 +257,14 @@ def main(): comment = etree.Comment(comment_text) grit_root.addprevious(comment) + # Fix output filenames to generate "brave" files instead of "chromium". + if basename in ('brave_strings', 'components_brave_strings'): + for pak_filename in xml_tree.xpath( + "//output[re:test(@filename, '.*\\.(pak|xml)')]", + namespaces={"re": "http://exslt.org/regular-expressions"}): + pak_filename.attrib['filename'] = pak_filename.attrib[ + 'filename'].replace('chromium_strings', 'brave_strings') + print(f'writing file {source_string_path}') write_xml_file_from_tree(source_string_path, xml_tree) print('-----------') diff --git a/script/lib/l10n/grd_utils.py b/script/lib/l10n/grd_utils.py index bac74a22defd..25be5c38cc86 100755 --- a/script/lib/l10n/grd_utils.py +++ b/script/lib/l10n/grd_utils.py @@ -8,6 +8,7 @@ from collections import defaultdict import os +import posixpath import re import FP import lxml.etree # pylint: disable=import-error @@ -135,11 +136,13 @@ def get_override_file_path(source_string_path): # _override goes after the string name but before the _[locale].xtb part parts = basename.split('_') parts.insert(-1, 'override') - override_string_path = os.path.join(os.path.dirname(source_string_path), - '.'.join(('_'.join(parts), ext))) + override_string_path = posixpath.join( + os.path.dirname(source_string_path), '.'.join( + ('_'.join(parts), ext))) else: - override_string_path = os.path.join(os.path.dirname(source_string_path), - '.'.join((basename + '_override', ext))) + override_string_path = posixpath.join( + os.path.dirname(source_string_path), '.'.join( + (basename + '_override', ext))) return override_string_path diff --git a/test/BUILD.gn b/test/BUILD.gn index c02e0cd67d17..3f9b63d45df6 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -1233,24 +1233,18 @@ if (is_android) { "//base:base_java_test_support", "//brave/components/brave_wallet/common:mojom_java", "//chrome/android:chrome_apk_pak_assets", - "//chrome/android:chrome_public_base_module_java_for_test", "//chrome/browser/android/lifecycle:java", "//chrome/browser/back_press/android:java", "//chrome/browser/browser_controls/android:java", "//chrome/browser/contextmenu:java", "//chrome/browser/feed/android:java", - "//chrome/browser/flags:java", "//chrome/browser/fullscreen/android:java", - "//chrome/browser/language/android:java", "//chrome/browser/password_manager/android:java", - "//chrome/browser/preferences:java", "//chrome/browser/prefetch/android:java", - "//chrome/browser/privacy_sandbox/android:java", "//chrome/browser/profiles/android:java", "//chrome/browser/safe_browsing/android:java", "//chrome/browser/safety_check/android:java", "//chrome/browser/settings:test_support_java", - "//chrome/browser/share:java", "//chrome/browser/tab:java", "//chrome/browser/tabmodel:java", "//chrome/browser/ui/android/appmenu:java", @@ -1282,6 +1276,7 @@ if (is_android) { "//components/variations/android:variations_java", "//content/public/android:content_full_java", "//third_party/androidx:androidx_appcompat_appcompat_java", + "//third_party/androidx:androidx_fragment_fragment_java", "//third_party/androidx:androidx_preference_preference_java", "//third_party/androidx:androidx_recyclerview_recyclerview_java", "//third_party/androidx:androidx_test_runner_java", diff --git a/test/filters/browser_tests.filter b/test/filters/browser_tests.filter index cf9a0cc40244..5c3ec1e35c48 100644 --- a/test/filters/browser_tests.filter +++ b/test/filters/browser_tests.filter @@ -107,6 +107,7 @@ -SearchPreloadUnifiedFallbackBrowserTest.PrefetchSucceedAfterPrerenderFailed -SearchPreloadUnifiedFallbackBrowserTest.PrerenderHintReceivedAfterCompletion -SearchPreloadUnifiedFallbackBrowserTest.ServingToPrerenderingUntilCompletion +-SearchPreloadUnifiedFallbackBrowserTest.ServingToPrerenderNavigationTwice # These tests fail because of the following failed expectation in prerender_test_util.cc: # Expected: (host_id) != (RenderFrameHost::kNoFrameTreeNodeId), actual: -1 vs -1 @@ -123,6 +124,7 @@ -All/PrerenderingChangePasswordNavigationThrottleBrowserTest.* -All/PrerenderNewTabPageBrowserTest.NewTabPagePrerenderNonHttps/* -All/PrerenderNewTabPageBrowserTest.PrerenderTriggeredByNewTabPageAndActivate/* +-All/PrerenderNewTabPageBrowserTest.PrerenderTriggeredCanceled/* -All/PrerenderOmniboxSearchSuggestionReloadBrowserTest.* -All/SafeBrowsingBlockingPageDelayedWarningPrerenderingBrowserTest.* -All/SafeBrowsingPrerenderBrowserTest.* @@ -281,7 +283,10 @@ -IsolatedWebAppBrowserServiceWorkerTest.ServiceWorkerPartitioned -IsolatedWebAppBrowsingDataClearingTest.CacheCleared -IsolatedWebAppBrowsingDataClearingTest.ClearBrowserDataAllTime +-IsolatedWebAppBrowsingDataClearingTest.ClearBrowserDataTimeRanged -IsolatedWebAppBrowsingDataClearingTest.CookieCleared +-IsolatedWebAppBrowsingDataClearingTest.ControlledFrameClearSiteDataHeader +-IsolatedWebAppBrowsingDataClearingTest.CrossOriginIframeClearSiteDataHeader -IsolatedWebAppBrowsingDataClearingTest.DataClearedOnUninstall -IsolatedWebAppBrowsingDataClearingTest.LocalStorageCleared -IsolatedWebAppDevToolsTest.ErrorPage @@ -321,6 +326,7 @@ # These tests fail because we patch # AccountConsistencyModeManager::ComputeAccountConsistencyMethod to return # AccountConsistencyMethod::kDisabled +-ContextMenuWithFilteringForSupervisedUsersBrowserTest.SaveLinkAsEntryIsDisabledForUrlsBlockedByAsyncCheckerForChild -ContextMenuWithFilteringForSupervisedUsersBrowserTest.SaveLinkAsEntryIsEnabledForUrlsAllowedByAsyncCheckerForChild -ContextMenuWithoutFilteringForSupervisedUsersBrowserTest.SaveLinkAsEntryIsDisabledForUrlsBlockedByAsyncCheckerForChild -ContextMenuWithoutFilteringForSupervisedUsersBrowserTest.SaveLinkAsEntryIsEnabledForUrlsAllowedByAsyncCheckerForChild @@ -374,6 +380,9 @@ -BackgroundPage/ExtensionPreferenceApiTest.OnChangeSplit/0 -BackgroundPage/ExtensionPreferenceApiTest.Standard/0 -EventPage/ExtensionPreferenceApiEventPageTest.ThirdPartyCookiesAllowed/0 +-ThirdPartyPartitionedStorageAccessibilityCanBeDisabledTest.Basic/* +-ThirdPartyPartitionedStorageAccessibilitySharedWorkerTest.* +-ThirdPartyPartitionedStorageAccessibilityTest.* # These tests fail because we disable creation of CookieControlsIconView in # PageActionIconController::Init's switch @@ -398,7 +407,7 @@ # is coming from Brave extension? -PrivacyBudgetBrowserTestWithTestRecorderParameterized/PrivacyBudgetBrowserTestWithTestRecorder.RecordingFeaturesCalledInWorker/* -# This test times out because we Disable "Use a prediction service to load +# These tests time out because we Disable "Use a prediction service to load # pages more quickly" (via prefetch::prefs::kNetworkPredictionOptions pref). -All/LoadingPredictorNetworkIsolationKeyBrowserTest.* -All/PredictionManagerBrowserTest.* @@ -563,8 +572,11 @@ # identity_manager->AreRefreshTokensLoaded() -EnterpriseWelcomeUIDialogPixelTest.InvokeUi_default/* -EnterpriseWelcomeUIWindowPixelTest.InvokeUi_default/* +-ForceSigninProfilePickerCreationFlowBrowserTest.ForceSigninAbortedBySyncDeclined +-ForceSigninProfilePickerCreationFlowBrowserTest.ForceSigninSuccessful -GaiaRemoteConsentFlowParamBrowserTest.* -PasswordRevampedManagementBubbleBrowserTest.InvokeUi_ManagePasswordBubbleWithRevampedDesign/* +-PlusAddressServiceBrowserTest.VerifySupportsPlusAddresses -SyncConfirmationUIDialogPixelTest.InvokeUi_default/* -SyncConfirmationUIWindowPixelTest.InvokeUi_default/* @@ -576,6 +588,8 @@ -All/SupervisedUserServiceBrowserTest.ProfileName/Regular -All/SupervisedUserServiceBrowserTest.ProfileName/Supervised -IpProtectionAuthTokenProviderBrowserTest.NetworkServiceCanRequestTokens +-IpProtectionConfigProviderBrowserTest.ExpectedReceiverSetStateAfterNetworkServiceCrash +-IpProtectionConfigProviderBrowserTest.NetworkServiceCanRequestTokens -SupervisionRemovalExtensionTest.RemoveCustodianApprovalRequirement # These tests fail or time out because IdentityManager never loads refresh @@ -602,7 +616,7 @@ -SystemNetworkContextManagerWithCustomProxyConfigBrowserTest.InitialCustomProxyConfig -SystemNetworkContextManagerWithIpProtectionFlagsEnabledAndCommandLineSettingsEnabled.EnableIpProtectionProxyCommandLineOverridesFeature -# These tests fail because we disable DIPS via dips::kFeature +# These tests fail because we disable DIPS via features::kDIPS -All/DIPSSiteDataAccessDetectorTest.AttributeSameSiteIframesSiteDataAccessTo1P/* -All/DIPSSiteDataAccessDetectorTest.AttributeSameSiteNestedIframesSiteDataAccessTo1P/* -All/DIPSSiteDataAccessDetectorTest.DiscardFencedFrameCookieClientAccess/* @@ -618,6 +632,7 @@ -All/PermissionPromptBubbleBaseViewBrowserTest.InvokeUi_storage_access/* -AutoPictureInPictureTabHelperBrowserTest.ImmediatelyClosesAutopipIfTabIsAlreadyFocused -AutoPictureInPictureTabHelperBrowserTest.OpensAndClosesVideoAutopip +-AutoPictureInPictureTabHelperBrowserTest.RespectsAutoPictureInPictureContentSetting -AutoPictureInPictureTabHelperBrowserTest.ShowsMostRecentlyHiddenTab -DeviceChooserExtensionBrowserTests/DeviceChooserExtensionBrowserTest.ChooserAnchoredToExtensionIcon/WebHid -DeviceChooserExtensionBrowserTests/DeviceChooserExtensionBrowserTest.ChooserAnchoredToExtensionIcon/WebUsb @@ -716,109 +731,15 @@ # These tests crash because we disable # enterprise_connectors::kLocalContentAnalysisEnabled feature -All/ContentAnalysisAfterPrintPreviewBrowserTest.*/* --All/ContentAnalysisBeforePrintPreviewBrowserTest.PrintWithPreview/4 --All/ContentAnalysisBeforePrintPreviewBrowserTest.PrintWithPreview/5 --All/ContentAnalysisBeforePrintPreviewBrowserTest.PrintWithPreview/6 --All/ContentAnalysisBeforePrintPreviewBrowserTest.PrintWithPreview/7 --All/ContentAnalysisBeforePrintPreviewBrowserTest.SystemPrintFromPrintPreview/4 --All/ContentAnalysisBeforePrintPreviewBrowserTest.SystemPrintFromPrintPreview/5 --All/ContentAnalysisBeforePrintPreviewBrowserTest.SystemPrintFromPrintPreview/6 --All/ContentAnalysisBeforePrintPreviewBrowserTest.SystemPrintFromPrintPreview/7 --All/ContentAnalysisBeforePrintPreviewBrowserTest.WindowDotPrint/4 --All/ContentAnalysisBeforePrintPreviewBrowserTest.WindowDotPrint/6 +-All/ContentAnalysisBeforePrintPreviewBrowserTest.PrintWithPreview/* +-All/ContentAnalysisBeforePrintPreviewBrowserTest.SystemPrintFromPrintPreview/* +-All/ContentAnalysisBeforePrintPreviewBrowserTest.WindowDotPrint/* -All/ContentAnalysisScriptedPreviewlessPrintAfterDialogBrowserTest.*/* -All/ContentAnalysisScriptedPreviewlessPrintBeforeDialogBrowserTest.*/* -ConnectorsServiceAnalysisProfileBrowserTest.Affiliation/* --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/1 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/10 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/11 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/13 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/14 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/15 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/17 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/18 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/19 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/2 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/21 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/22 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/23 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/26 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/27 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/3 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/30 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/31 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/34 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/35 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/38 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/39 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/42 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/43 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/46 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/47 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/5 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/6 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/7 --ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/9 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/1 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/10 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/11 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/13 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/14 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/15 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/17 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/18 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/19 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/2 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/21 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/22 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/23 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/26 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/27 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/3 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/30 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/31 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/34 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/35 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/38 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/39 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/42 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/43 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/46 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/47 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/5 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/6 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/7 --ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/9 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/1 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/10 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/11 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/13 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/14 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/15 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/17 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/18 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/19 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/2 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/21 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/22 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/23 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/26 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/27 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/3 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/30 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/31 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/34 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/35 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/38 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/39 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/42 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/43 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/46 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/47 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/5 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/6 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/7 --ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/9 +-ConnectorsServiceAnalysisProfileBrowserTest.DeviceReporting/* +-ConnectorsServiceAnalysisProfileBrowserTest.NoReporting/* +-ConnectorsServiceAnalysisProfileBrowserTest.ProfileReporting/* -ContentAnalysisDialogAppearanceBrowserTest.* -ContentAnalysisDialogCustomMessageAppearanceBrowserTest.* -EnterpriseReportingPrivateGetContextInfoBaseBrowserTest.TestAllProviderNamesSet @@ -873,7 +794,8 @@ -WebHidExtensionBrowserTest.DeviceConnectAndOpenDeviceWhenServiceWorkerStopped -WebHidExtensionBrowserTest.HidConnectionTracker -WebHidExtensionFeatureEnabledBrowserTest.HidConnectionTracker --WebUsbExtensionFeatureEnabledBrowserTest.UsbConnectionTracker +-WebUsbExtensionBrowserTest.DeviceConnectAndOpenDeviceWhenServiceWorkerStopped +-WebUsbExtensionBrowserTest.UsbConnectionTracker # These tests fail because we disable field trials via # disable_fieldtrial_testing_config @@ -897,6 +819,7 @@ -All/BrowserFrameColorProviderTest.BaselineThemeIgnoresNativeThemeColor/1 -All/BrowserFrameColorProviderTest.BrowserFrameTracksBrowserColorVariant/1 -All/BrowserFrameColorProviderTest.BrowserFrameTracksIsGrayscale/1 +-All/BrowserFrameColorProviderTest.GrayscaleIgnoresUserColor/1 -All/BrowserFrameColorProviderTest.GrayscaleUsesBaselinePalette/1 -All/BrowserFrameColorProviderTest.IncognitoAlwaysDarkMode/1 -All/BrowserFrameColorProviderTest.IncognitoAlwaysIgnoresUserColor/1 @@ -905,6 +828,7 @@ -All/BrowserFrameColorProviderTest.UseDeviceIgnoresTheme/1 -All/BrowserFrameColorProviderTest.UserColorProfilePrefTrackedCorrectly/1 -All/BrowserFrameColorProviderTest.UserColorTracksAutogeneratedThemeColor/1 +-All/NativeChromeColorMixerWinBrowsertest.HeaderColorsFollowAccentColor/* -AppMenuBrowserTestRefreshOnly.* -BrowserCommandControllerBrowserTestRefreshOnly.* -FirstRunIntroPixelTest.InvokeUi_default/CR2023 @@ -971,6 +895,15 @@ -All/PageInfoBubbleViewBrowserTestCookiesSubpage.LinkInDescriptionForCookiesSettings/* -All/PageInfoBubbleViewBrowserTestCookiesSubpage.ToggleForBlockingThirdPartyCookies/1 +# These tests fail because we disable Journeys via +# history_clusters::internal::kJourneys +-RenameJourneys/HistoryClustersPolicyTest.HistoryClustersVisible/* + +# These tests fail because we patch safe_browsing::IsEnhancedProtectionEnabled +# to return false +-ExtensionTelemetryServiceBrowserTest.* +-ExtensionTelemetryServiceBrowserTestWithInterceptRemoteHostsContactedInRendererEnabled.InterceptsRemoteHostContactedSignalInRenderer + # Tests below this point have not been diagnosed or had issues created yet. -_/WebrtcLoggingPrivateApiStartEventLoggingTestFeatureAndPolicyEnabled.* -AccessCodeCastHandlerBrowserTest.* @@ -1164,6 +1097,7 @@ -DevToolsNetInfoTest.* -DevToolsPolicyTest.* -DevToolsProtocolTest.* +-DevToolsProtocolTest_PrefetchHoldbackDisabledIfCDPClientConnected.* -DevToolsSyncTest.* -DevToolsTagTest.* -DevToolsTest.NewWindowFromBrowserContext @@ -1218,7 +1152,6 @@ -ExtensionSettingsUIBrowserTest.* -ExtensionTabUtilBrowserTest.* -ExtensionTagsTest.* --ExtensionTelemetryServiceBrowserTest.* -ExtensionUninstallDialogViewInteractiveBrowserTest.* -ExtensionURLRewriteBrowserTest.* -ExtensionWebRequestApiTest.* @@ -1301,6 +1234,7 @@ -IncognitoProfileMainNetworkContext/NetworkContextConfigurationManagedProxySettingsBrowserTest.* -IncognitoProfileMainNetworkContext/NetworkContextConfigurationProxyOnStartBrowserTest.* -IncognitoProfileMainNetworkContext/NetworkContextConfigurationProxySettingsBrowserTest.* +-InspectUISharedStorageTest.* -InspectUITest.* -IntentChipButtonBrowserTest.* -IntentChipButtonSkipIntentPickerBrowserTest.ClickingChipOpensApp @@ -1455,7 +1389,9 @@ -ProfileKeyedServiceBrowserTest.GuestProfileOTR_NeededServices -ProfileKeyedServiceBrowserTest.GuestProfileParent_NeededServices -ProfileKeyedServiceBrowserTest.SystemProfileOTR_NeededServices +-ProfileKeyedServiceBrowserTest.SystemProfileOTR_ServicesThatCanBeCreated -ProfileKeyedServiceBrowserTest.SystemProfileParent_NeededServices +-ProfileKeyedServiceBrowserTest.SystemProfileParent_ServicesThatCanBeCreated -ProfileListDesktopBrowserTest.* -ProfileMainNetworkContext/NetworkContextConfigurationBrowserTest.* -ProfileMainNetworkContext/NetworkContextConfigurationDataPacBrowserTest.* diff --git a/test/filters/unit_tests-linux.filter b/test/filters/unit_tests-linux.filter index 081eb9994d07..51f32879cc19 100644 --- a/test/filters/unit_tests-linux.filter +++ b/test/filters/unit_tests-linux.filter @@ -8,7 +8,7 @@ # These fail because we override IdentityManager::GetAccountsInCookieJar -SupervisedUserURLFilterTest.UrlsNotRequiringGuardianApprovalAllowed -# These fail because we disable DIPS via dips::kFeature +# These fail because we disable DIPS via features::kDIPS -All/DIPSDatabasePopupsTest.* -DIPSDatabaseBounceTableGarbageCollectionTest.* diff --git a/test/filters/unit_tests.filter b/test/filters/unit_tests.filter index 83d57afcefa7..e113bdab32b8 100644 --- a/test/filters/unit_tests.filter +++ b/test/filters/unit_tests.filter @@ -32,10 +32,15 @@ -ApcScrimManagerImplTest.UpdatesVisibilityOnWebcontentsVisibilityChanged -BatterySaverButtonNoExperimentsAvailableTest.* -BatterySaverButtonTest.* +-BookmarkBubbleViewShoppingCollectionTest.* +-BookmarkBubbleViewTest.* -BrowserFeaturePromoControllerViewsTest.* -BrowserFinderTest.ScheduledForDeletion +-BrowserViewPipTest.CanFullscreenPolicyDoesNotEnableFullscreen -BrowserViewTestWithStopLoadingAnimationForHiddenWindow.LoadingAnimationNotRenderedWhenWindowHidden -ChromeBrowsingDataRemoverDelegateOriginTrialsTest.PersistentOriginTrialsAreDeleted +-ChromeTailoredSecurityServiceRetryForSyncUsersDisabledTest.* +-ChromeTailoredSecurityServiceTest.* -CookieControlsBubbleCoordinatorTest.ShowBubbleTest -CookieControlsBubbleViewImplTest.BubbleWidth -CookieControlsContentViewUnitTest.FeedbackSection @@ -75,6 +80,7 @@ -MandatoryReauthBubbleControllerImplTest.SuccessfullyInvokesAcceptCallback -MandatoryReauthBubbleControllerImplTest.SuccessfullyInvokesCancelCallback -MandatoryReauthBubbleControllerImplTest.SuccessfullyInvokesCloseCallback +-OverscrollPrefManagerTest.PrefChange -PageLiveStateDecoratorHelperTabsTest.IsActiveTab -PageLiveStateDecoratorHelperTabsTest.IsPinnedTab -PeopleHandlerSignoutTest.RevokeSyncNotAllowed @@ -116,15 +122,16 @@ # TestExtensionSystem # https://github.com/brave/brave-browser/issues/25727 -AppHomePageHandlerTest.* --ChromeUsbDelegateExtensionRenderFrameFeatureEnabledTest.OpenAndCloseDevice --ChromeUsbDelegateExtensionRenderFrameFeatureEnabledTest.OpenAndDisconnectDevice +-ChromeUsbDelegateExtensionRenderFrameFeatureDisabledTest.* +-ChromeUsbDelegateExtensionRenderFrameFeatureEnabledTest.* -ChromeUsbDelegateExtensionRenderFrameTest.* +-ChromeUsbDelegateExtensionServiceWorkerFeatureDisabledTest.* -ChromeUsbDelegateExtensionServiceWorkerFeatureEnabledTest.* --ChromeUsbDelegateExtensionServiceWorkerTest.WebUsbServiceNotConnected +-ChromeUsbDelegateExtensionServiceWorkerTest.* -ChromeUsbDelegateImprivataExtensionRenderFrameTest.AllowlistedImprivataExtension --ChromeUsbDelegateImprivataExtensionServiceWorkerFeatureEnabledTest.AllowlistedImprivataExtension +-ChromeUsbDelegateImprivataExtensionServiceWorkerTest.* -ChromeUsbDelegateSmartCardExtensionRenderFrameTest.AllowlistedSmartCardConnectorExtension --ChromeUsbDelegateSmartCardExtensionServiceWorkerFeatureEnabledTest.AllowlistedSmartCardConnectorExtension +-ChromeUsbDelegateSmartCardExtensionServiceWorkerTest.* # These tests fail because we customize the download status messages with our # own verbiage @@ -211,7 +218,7 @@ -DiceTurnSyncOnHelperTest.* -DiceWebSigninInterceptorForcedSeparationTest.* -DiceWebSigninInterceptorTest.* --GAIAInfoUpdateServiceDiceTest.* +-GAIAInfoUpdateServiceTest.* # This test fails because we disable the privacy sandbox -PrivacySandboxServiceTest.MetricsLoggingOccursCorrectly @@ -224,13 +231,15 @@ # features::kEarlyHintsPreloadForNavigation -PreconnectManagerTest.* -# These tests fail because we disable DIPS via dips::kFeature +# These tests fail because we disable DIPS via features::kDIPS -All/DIPSDatabaseAllColumnTest.*/* -All/DIPSDatabaseErrorHistogramsTest.*/* -All/DIPSDatabaseGarbageCollectionTest.*/* -All/DIPSDatabaseInteractionTest.*/* +-All/DIPSDatabasePopupsTest.*/* -BrowserSigninDetectorServiceTest.LateObservation -CreateChooserTitleTest.ExtensionsFrameTree +-DIPSDatabaseBounceTableGarbageCollectionTest.* -DIPSDatabaseHistogramTest.* -DIPSGetSitesToClearTest.* -DIPSServiceHistogramTest.* @@ -250,6 +259,7 @@ -CWSInfoServiceTest.* -LocalTabHandlerTest.* -PermissionPromptBubbleTwoOriginsViewTest.DiesIfPermissionNotAllowed +-PermissionPromptBubbleTwoOriginsViewTest.LinkIsPresent -PermissionPromptBubbleTwoOriginsViewTest.TitleMentionsTwoOriginsAndPermission -SavedTabGroupKeyedServiceUnitTest.* -TabLifecycleUnitTest.CannotDiscardPictureInPictureWindow @@ -333,6 +343,8 @@ -All/ClientSideDetectionServiceTest.GetNumReportTestESB/3 -All/ClientSideDetectionServiceTest.GetNumReportTestESB/6 -All/ClientSideDetectionServiceTest.GetNumReportTestESB/7 +-All/ClientSideDetectionServiceTest.TestReceivingImageEmbedderUpdatesAfterResubscription/1 +-All/ClientSideDetectionServiceTest.TestReceivingImageEmbedderUpdatesAfterResubscription/3 -All/ClientSideDetectionServiceTest.TestReceivingImageEmbedderUpdatesAfterResubscription/5 -All/ClientSideDetectionServiceTest.TestReceivingImageEmbedderUpdatesAfterResubscription/7 -ChromePingManagerFactoryTest.ShouldFetchAccessTokenForReport_Yes @@ -387,10 +399,18 @@ # optimization_guide::features::kOptimizationGuideFetchingForSRP -ChromeHintsManagerFetchingTest.HintsFetched_* -# These test fail because we remove description and 3p cookies toggle from the +# This test fails because we remove description and 3p cookies toggle from the # Page Info cookies view. -PageInfoBubbleViewCookiesSubpageTest.TextsOnButtonsAreCorrect +# This test fails because we patch safe_browsing::IsEnhancedProtectionEnabled to +# return false +-SafetyHubHandlerTest.HandleGetSafeBrowsingState_EnabledEnhanced + +# This test times out because we Disable "Use a prediction service to load +# pages more quickly" (via prefetch::prefs::kNetworkPredictionOptions pref) +-NavigationPredictorUserInteractionsTest.ProcessPointerEventUsingMLModel + # Tests below this point have not been diagnosed or had issues created yet. -AboutFlagsHistogramTest.* -AboutFlagsTest.* @@ -434,7 +454,6 @@ -BlocklistStatesInteractionUnitTest.* -BookmarkBarViewInWidgetTest.* -BookmarkBarViewTest.* --BookmarkBubbleViewTest.* -BookmarkManagerPrivateApiUnitTest.* -BookmarkMenuDelegateTest.* -BookmarkTest.* @@ -493,7 +512,6 @@ -ChromePingManagerTest.* -ChromeRuntimeAPIDelegateReloadTest.* -ChromeRuntimeAPIDelegateTest.* --ChromeTailoredSecurityServiceTest.* -ChromeUsbDelegateTest.* -ChromeWebContentsMenuHelperUnitTest.* -ChromeWebContentsViewDelegateViewsTest.* diff --git a/third_party/blink/renderer/core/brave_page_graph/blink_converters.cc b/third_party/blink/renderer/core/brave_page_graph/blink_converters.cc index 6d097ae9d67c..6e2bb8a77bde 100644 --- a/third_party/blink/renderer/core/brave_page_graph/blink_converters.cc +++ b/third_party/blink/renderer/core/brave_page_graph/blink_converters.cc @@ -54,10 +54,9 @@ String ToPageGraphBlinkArg(TextMetrics* result) { << ", emHeightAscent: " << result->emHeightAscent() << ", emHeightDescent: " << result->emHeightDescent(); - Baselines* baselines = result->getBaselines(); - result_buffer << ", hangingBaseline: " << baselines->hanging() - << ", alphabeticBaseline: " << baselines->alphabetic() - << ", ideographicBaseline: " << baselines->ideographic(); + result_buffer << ", hangingBaseline: " << result->hangingBaseline() + << ", alphabeticBaseline: " << result->alphabeticBaseline() + << ", ideographicBaseline: " << result->ideographicBaseline(); return String(result_buffer.str()); } diff --git a/third_party/rust/Cargo.toml b/third_party/rust/Cargo.toml index 104f180e105e..536f1527e99b 100644 --- a/third_party/rust/Cargo.toml +++ b/third_party/rust/Cargo.toml @@ -609,7 +609,7 @@ path = "group/v0_12/crate" package = "group" [patch.crates-io.hashbrown_v0_11] -path = "../../../third_party/rust/hashbrown/v0_11/crate" +path = "hashbrown/v0_11/crate" package = "hashbrown" [patch.crates-io.hashbrown_v0_12] @@ -669,7 +669,7 @@ path = "idna/v0_3/crate" package = "idna" [patch.crates-io.indexmap_v1] -path = "../../../third_party/rust/indexmap/v1/crate" +path = "indexmap/v1/crate" package = "indexmap" [patch.crates-io.iovec_v0_1] @@ -817,7 +817,7 @@ path = "num_traits/v0_2/crate" package = "num-traits" [patch.crates-io.once_cell_v1] -path = "../../../third_party/rust/once_cell/v1/crate" +path = "once_cell/v1/crate" package = "once_cell" [patch.crates-io.opaque-debug_v0_3] @@ -1237,7 +1237,7 @@ path = "tinyvec/v1/crate" package = "tinyvec" [patch.crates-io.toml_v0_5] -path = "../../../third_party/rust/toml/v0_5/crate" +path = "toml/v0_5/crate" package = "toml" [patch.crates-io.tracing-attributes_v0_1] diff --git a/third_party/rust/adblock/v0_8/BUILD.gn b/third_party/rust/adblock/v0_8/BUILD.gn index 6d4c111f49ea..671501f01b0d 100644 --- a/third_party/rust/adblock/v0_8/BUILD.gn +++ b/third_party/rust/adblock/v0_8/BUILD.gn @@ -58,6 +58,7 @@ cargo_crate("lib") { "//brave/third_party/rust/cssparser/v0_28:lib", "//brave/third_party/rust/idna/v0_2:lib", "//brave/third_party/rust/itertools/v0_10:lib", + "//brave/third_party/rust/once_cell/v1:lib", "//brave/third_party/rust/percent_encoding/v2:lib", "//brave/third_party/rust/rmp_serde/v0_15:lib", "//brave/third_party/rust/seahash/v3:lib", @@ -67,7 +68,6 @@ cargo_crate("lib") { "//third_party/rust/base64/v0_13:lib", "//third_party/rust/bitflags/v1:lib", "//third_party/rust/memchr/v2:lib", - "//third_party/rust/once_cell/v1:lib", "//third_party/rust/regex/v1:lib", "//third_party/rust/serde/v1:lib", ] diff --git a/third_party/rust/ahash/v0_7/BUILD.gn b/third_party/rust/ahash/v0_7/BUILD.gn index 3c094763e769..aeef8b80ac58 100644 --- a/third_party/rust/ahash/v0_7/BUILD.gn +++ b/third_party/rust/ahash/v0_7/BUILD.gn @@ -46,7 +46,7 @@ cargo_crate("lib") { library_configs += [ "//build/config/compiler:no_chromium_code" ] executable_configs -= [ "//build/config/compiler:chromium_code" ] executable_configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ "//third_party/rust/once_cell/v1:lib" ] + deps = [ "//brave/third_party/rust/once_cell/v1:lib" ] if (is_linux || is_chromeos || is_android || is_win || is_ios || is_fuchsia) { deps += [ "//third_party/rust/getrandom/v0_2:lib" ] } diff --git a/third_party/rust/hashbrown/v0_11/BUILD.gn b/third_party/rust/hashbrown/v0_11/BUILD.gn new file mode 100644 index 000000000000..f06b35914c43 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/BUILD.gn @@ -0,0 +1,61 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# @generated from third_party/rust/BUILD.gn.hbs by tools/crates/gnrt. +# Do not edit! + +import("//build/rust/cargo_crate.gni") + +cargo_crate("lib") { + crate_name = "hashbrown" + epoch = "0.11" + crate_type = "rlib" + + # Only for usage from third-party crates. Add the crate to + # third_party.toml to use it from first-party code. + visibility = [ "//brave/third_party/rust/*" ] + crate_root = "crate/src/lib.rs" + sources = [ + "//brave/third_party/rust/hashbrown/v0_11/crate/benches/bench.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/mod.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/helpers.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/map.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/mod.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/raw.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/set.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/serde.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/lib.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/macros.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/map.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/raw/alloc.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/raw/bitmask.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/raw/generic.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/raw/mod.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/raw/sse2.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/rustc_entry.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/scopeguard.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/src/set.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/tests/hasher.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/tests/rayon.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/tests/serde.rs", + "//brave/third_party/rust/hashbrown/v0_11/crate/tests/set.rs", + ] + inputs = [ + "//brave/third_party/rust/hashbrown/v0_11/crate/CHANGELOG.md", + "//brave/third_party/rust/hashbrown/v0_11/crate/README.md", + ] + + # Unit tests skipped. Generate with --with-tests to include them. + build_native_rust_unit_tests = false + edition = "2018" + cargo_pkg_version = "0.11.2" + cargo_pkg_authors = "Amanieu d'Antras " + cargo_pkg_name = "hashbrown" + cargo_pkg_description = "A Rust port of Google's SwissTable hash map" + library_configs -= [ "//build/config/compiler:chromium_code" ] + library_configs += [ "//build/config/compiler:no_chromium_code" ] + executable_configs -= [ "//build/config/compiler:chromium_code" ] + executable_configs += [ "//build/config/compiler:no_chromium_code" ] + features = [ "raw" ] +} diff --git a/third_party/rust/hashbrown/v0_11/README.chromium b/third_party/rust/hashbrown/v0_11/README.chromium new file mode 100644 index 000000000000..0aa3c15b5e4e --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/README.chromium @@ -0,0 +1,7 @@ +Name: hashbrown +URL: https://crates.io/crates/hashbrown +Description: A Rust port of Google's SwissTable hash map +Version: 0.11.2 +Security Critical: no +Shipped: yes +License: Apache 2.0 diff --git a/third_party/rust/hashbrown/v0_11/crate/.cargo_vcs_info.json b/third_party/rust/hashbrown/v0_11/crate/.cargo_vcs_info.json new file mode 100644 index 000000000000..0eb38240e067 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "bbb5d3bb1c23569c15e54c670bc0c3669ae3e7dc" + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/.gitignore b/third_party/rust/hashbrown/v0_11/crate/.gitignore new file mode 100644 index 000000000000..693699042b1a --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/third_party/rust/hashbrown/v0_11/crate/CHANGELOG.md b/third_party/rust/hashbrown/v0_11/crate/CHANGELOG.md new file mode 100644 index 000000000000..c88d3e0fea66 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/CHANGELOG.md @@ -0,0 +1,342 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.11.2] - 2021-03-25 + +## Fixed + +- Added missing allocator type parameter to `HashMap`'s and `HashSet`'s `Clone` impls. (#252) + +## [v0.11.1] - 2021-03-20 + +## Fixed + +- Added missing `pub` modifier to `BumpWrapper`. (#251) + +## [v0.11.0] - 2021-03-14 + +## Added +- Added safe `try_insert_no_grow` method to `RawTable`. (#229) +- Added support for `bumpalo` as an allocator without the `nightly` feature. (#231) +- Implemented `Default` for `RawTable`. (#237) +- Added new safe methods `RawTable::get_each_mut`, `HashMap::get_each_mut`, and + `HashMap::get_each_key_value_mut`. (#239) +- Added `From>` for `HashSet`. (#235) +- Added `try_insert` method to `HashMap`. (#247) + +## Changed +- The minimum Rust version has been bumped to 1.49.0. (#230) +- Significantly improved compilation times by reducing the amount of generated IR. (#205) + +## Removed +- We no longer re-export the unstable allocator items from the standard library, nor the stable shims approximating the same. (#227) +- Removed hasher specialization support from `aHash`, which was resulting in inconsistent hashes being generated for a key. (#248) + +## Fixed +- Fixed union length comparison. (#228) + +## ~~[v0.10.0] - 2021-01-16~~ + +This release was _yanked_ due to inconsistent hashes being generated with the `nightly` feature. (#248) + +## Changed +- Parametrized `RawTable`, `HashSet` and `HashMap` over an allocator. (#133) +- Improved branch prediction hints on stable. (#209) +- Optimized hashing of primitive types with AHash using specialization. (#207) +- Only instantiate `RawTable`'s reserve functions once per key-value. (#204) + +## [v0.9.1] - 2020-09-28 + +## Added +- Added safe methods to `RawTable` (#202): + - `get`: `find` and `as_ref` + - `get_mut`: `find` and `as_mut` + - `insert_entry`: `insert` and `as_mut` + - `remove_entry`: `find` and `remove` + - `erase_entry`: `find` and `erase` + +## Changed +- Removed `from_key_hashed_nocheck`'s `Q: Hash`. (#200) +- Made `RawTable::drain` safe. (#201) + +## [v0.9.0] - 2020-09-03 + +### Fixed +- `drain_filter` now removes and yields items that do match the predicate, + rather than items that don't. This is a **breaking change** to match the + behavior of the `drain_filter` methods in `std`. (#187) + +### Added +- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190) +- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188) + +### Changed +- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193) +- Updated `ahash` dependency to 0.4. (#198) +- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195) +- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`, + `with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185) + +## [v0.8.2] - 2020-08-08 + +### Changed +- Avoid closures to improve compile times. (#183) +- Do not iterate to drop if empty. (#182) + +## [v0.8.1] - 2020-07-16 + +### Added +- Added `erase` and `remove` to `RawTable`. (#171) +- Added `try_with_capacity` to `RawTable`. (#174) +- Added methods that allow re-using a `RawIter` for `RawDrain`, + `RawIntoIter`, and `RawParIter`. (#175) +- Added `reflect_remove` and `reflect_insert` to `RawIter`. (#175) +- Added a `drain_filter` function to `HashSet`. (#179) + +### Changed +- Deprecated `RawTable::erase_no_drop` in favor of `erase` and `remove`. (#176) +- `insert_no_grow` is now exposed under the `"raw"` feature. (#180) + +## [v0.8.0] - 2020-06-18 + +### Fixed +- Marked `RawTable::par_iter` as `unsafe`. (#157) + +### Changed +- Reduced the size of `HashMap`. (#159) +- No longer create tables with a capacity of 1 element. (#162) +- Removed `K: Eq + Hash` bounds on `retain`. (#163) +- Pulled in `HashMap` changes from rust-lang/rust (#164): + - `extend_one` support on nightly. + - `CollectionAllocErr` renamed to `TryReserveError`. + - Added `HashSet::get_or_insert_owned`. + - `Default` for `HashSet` no longer requires `T: Eq + Hash` and `S: BuildHasher`. + +## [v0.7.2] - 2020-04-27 + +### Added +- Added `or_insert_with_key` to `Entry`. (#152) + +### Fixed +- Partially reverted `Clone` optimization which was unsound. (#154) + +### Changed +- Disabled use of `const-random` by default, which prevented reproducible builds. (#155) +- Optimized `repeat` function. (#150) +- Use `NonNull` for buckets, which improves codegen for iterators. (#148) + +## [v0.7.1] - 2020-03-16 + +### Added +- Added `HashMap::get_key_value_mut`. (#145) + +### Changed +- Optimized `Clone` implementation. (#146) + +## [v0.7.0] - 2020-01-31 + +### Added +- Added a `drain_filter` function to `HashMap`. (#135) + +### Changed +- Updated `ahash` dependency to 0.3. (#141) +- Optimized set union and intersection. (#130) +- `raw_entry` can now be used without requiring `S: BuildHasher`. (#123) +- `RawTable::bucket_index` can now be used under the `raw` feature. (#128) + +## [v0.6.3] - 2019-10-31 + +### Added +- Added an `ahash-compile-time-rng` feature (enabled by default) which allows disabling the + `compile-time-rng` feature in `ahash` to work around a Cargo bug. (#125) + +## [v0.6.2] - 2019-10-23 + +### Added +- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between + runtime performance and compilation time. (#119) + +## [v0.6.1] - 2019-10-04 + +### Added +- Added `Entry::insert` and `RawEntryMut::insert`. (#118) + +### Changed +- `Group::static_empty` was changed from a `const` to a `static` (#116). + +## [v0.6.0] - 2019-08-13 + +### Fixed +- Fixed AHash accidentally depending on `std`. (#110) + +### Changed +- The minimum Rust version has been bumped to 1.32 (due to `rand` dependency). + +## ~~[v0.5.1] - 2019-08-04~~ + +This release was _yanked_ due to a breaking change for users of `no-default-features`. + +### Added +- The experimental and unsafe `RawTable` API is available under the "raw" feature. (#108) +- Added entry-like methods for `HashSet`. (#98) + +### Changed +- Changed the default hasher from FxHash to AHash. (#97) +- `hashbrown` is now fully `no_std` on recent Rust versions (1.36+). (#96) + +### Fixed +- We now avoid growing the table during insertions when it wasn't necessary. (#106) +- `RawOccupiedEntryMut` now properly implements `Send` and `Sync`. (#100) +- Relaxed `lazy_static` version. (#92) + +## [v0.5.0] - 2019-06-12 + +### Fixed +- Resize with a more conservative amount of space after deletions. (#86) + +### Changed +- Exposed the Layout of the failed allocation in CollectionAllocErr::AllocErr. (#89) + +## [v0.4.0] - 2019-05-30 + +### Fixed +- Fixed `Send` trait bounds on `IterMut` not matching the libstd one. (#82) + +## [v0.3.1] - 2019-05-30 + +### Fixed +- Fixed incorrect use of slice in unsafe code. (#80) + +## [v0.3.0] - 2019-04-23 + +### Changed +- Changed shrink_to to not panic if min_capacity < capacity. (#67) + +### Fixed +- Worked around emscripten bug emscripten-core/emscripten-fastcomp#258. (#66) + +## [v0.2.2] - 2019-04-16 + +### Fixed +- Inlined non-nightly lowest_set_bit_nonzero. (#64) +- Fixed build on latest nightly. (#65) + +## [v0.2.1] - 2019-04-14 + +### Changed +- Use for_each in map Extend and FromIterator. (#58) +- Improved worst-case performance of HashSet.is_subset. (#61) + +### Fixed +- Removed incorrect debug_assert. (#60) + +## [v0.2.0] - 2019-03-31 + +### Changed +- The code has been updated to Rust 2018 edition. This means that the minimum + Rust version has been bumped to 1.31 (2018 edition). + +### Added +- Added `insert_with_hasher` to the raw_entry API to allow `K: !(Hash + Eq)`. (#54) +- Added support for using hashbrown as the hash table implementation in libstd. (#46) + +### Fixed +- Fixed cargo build with minimal-versions. (#45) +- Fixed `#[may_dangle]` attributes to match the libstd `HashMap`. (#46) +- ZST keys and values are now handled properly. (#46) + +## [v0.1.8] - 2019-01-14 + +### Added +- Rayon parallel iterator support (#37) +- `raw_entry` support (#31) +- `#[may_dangle]` on nightly (#31) +- `try_reserve` support (#31) + +### Fixed +- Fixed variance on `IterMut`. (#31) + +## [v0.1.7] - 2018-12-05 + +### Fixed +- Fixed non-SSE version of convert_special_to_empty_and_full_to_deleted. (#32) +- Fixed overflow in rehash_in_place. (#33) + +## [v0.1.6] - 2018-11-17 + +### Fixed +- Fixed compile error on nightly. (#29) + +## [v0.1.5] - 2018-11-08 + +### Fixed +- Fixed subtraction overflow in generic::Group::match_byte. (#28) + +## [v0.1.4] - 2018-11-04 + +### Fixed +- Fixed a bug in the `erase_no_drop` implementation. (#26) + +## [v0.1.3] - 2018-11-01 + +### Added +- Serde support. (#14) + +### Fixed +- Make the compiler inline functions more aggressively. (#20) + +## [v0.1.2] - 2018-10-31 + +### Fixed +- `clear` segfaults when called on an empty table. (#13) + +## [v0.1.1] - 2018-10-30 + +### Fixed +- `erase_no_drop` optimization not triggering in the SSE2 implementation. (#3) +- Missing `Send` and `Sync` for hash map and iterator types. (#7) +- Bug when inserting into a table smaller than the group width. (#5) + +## v0.1.0 - 2018-10-29 + +- Initial release + +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...HEAD +[v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2 +[v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1 +[v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0 +[v0.10.0]: https://github.com/rust-lang/hashbrown/compare/v0.9.1...v0.10.0 +[v0.9.1]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...v0.9.1 +[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0 +[v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2 +[v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1 +[v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0 +[v0.7.2]: https://github.com/rust-lang/hashbrown/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/rust-lang/hashbrown/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/rust-lang/hashbrown/compare/v0.6.3...v0.7.0 +[v0.6.3]: https://github.com/rust-lang/hashbrown/compare/v0.6.2...v0.6.3 +[v0.6.2]: https://github.com/rust-lang/hashbrown/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/rust-lang/hashbrown/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/rust-lang/hashbrown/compare/v0.5.1...v0.6.0 +[v0.5.1]: https://github.com/rust-lang/hashbrown/compare/v0.5.0...v0.5.1 +[v0.5.0]: https://github.com/rust-lang/hashbrown/compare/v0.4.0...v0.5.0 +[v0.4.0]: https://github.com/rust-lang/hashbrown/compare/v0.3.1...v0.4.0 +[v0.3.1]: https://github.com/rust-lang/hashbrown/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/rust-lang/hashbrown/compare/v0.2.2...v0.3.0 +[v0.2.2]: https://github.com/rust-lang/hashbrown/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-lang/hashbrown/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-lang/hashbrown/compare/v0.1.8...v0.2.0 +[v0.1.8]: https://github.com/rust-lang/hashbrown/compare/v0.1.7...v0.1.8 +[v0.1.7]: https://github.com/rust-lang/hashbrown/compare/v0.1.6...v0.1.7 +[v0.1.6]: https://github.com/rust-lang/hashbrown/compare/v0.1.5...v0.1.6 +[v0.1.5]: https://github.com/rust-lang/hashbrown/compare/v0.1.4...v0.1.5 +[v0.1.4]: https://github.com/rust-lang/hashbrown/compare/v0.1.3...v0.1.4 +[v0.1.3]: https://github.com/rust-lang/hashbrown/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/rust-lang/hashbrown/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-lang/hashbrown/compare/v0.1.0...v0.1.1 diff --git a/third_party/rust/hashbrown/v0_11/crate/Cargo.toml b/third_party/rust/hashbrown/v0_11/crate/Cargo.toml new file mode 100644 index 000000000000..02bd480e08fe --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/Cargo.toml @@ -0,0 +1,84 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "hashbrown" +version = "0.11.2" +authors = ["Amanieu d'Antras "] +exclude = [".travis.yml", "bors.toml", "/ci/*"] +description = "A Rust port of Google's SwissTable hash map" +readme = "README.md" +keywords = ["hash", "no_std", "hashmap", "swisstable"] +categories = ["data-structures", "no-std"] +license = "Apache-2.0/MIT" +repository = "https://github.com/rust-lang/hashbrown" +[package.metadata.docs.rs] +features = ["nightly", "rayon", "serde", "raw"] +[dependencies.ahash] +version = "0.7.0" +optional = true +default-features = false + +[dependencies.alloc] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-alloc" + +[dependencies.bumpalo] +version = "3.5.0" +optional = true + +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.rayon] +version = "1.0" +optional = true + +[dependencies.serde] +version = "1.0.25" +optional = true +default-features = false +[dev-dependencies.doc-comment] +version = "0.3.1" + +[dev-dependencies.fnv] +version = "1.0.7" + +[dev-dependencies.lazy_static] +version = "1.4" + +[dev-dependencies.rand] +version = "0.7.3" +features = ["small_rng"] + +[dev-dependencies.rayon] +version = "1.0" + +[dev-dependencies.serde_test] +version = "1.0" + +[features] +ahash-compile-time-rng = ["ahash/compile-time-rng"] +default = ["ahash", "inline-more"] +inline-more = [] +nightly = [] +raw = [] +rustc-dep-of-std = ["nightly", "core", "compiler_builtins", "alloc", "rustc-internal-api"] +rustc-internal-api = [] diff --git a/third_party/rust/hashbrown/v0_11/crate/Cargo.toml.orig b/third_party/rust/hashbrown/v0_11/crate/Cargo.toml.orig new file mode 100644 index 000000000000..a056c3c6b5b1 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/Cargo.toml.orig @@ -0,0 +1,59 @@ +[package] +name = "hashbrown" +version = "0.11.2" +authors = ["Amanieu d'Antras "] +description = "A Rust port of Google's SwissTable hash map" +license = "Apache-2.0/MIT" +repository = "https://github.com/rust-lang/hashbrown" +readme = "README.md" +keywords = ["hash", "no_std", "hashmap", "swisstable"] +categories = ["data-structures", "no-std"] +exclude = [".travis.yml", "bors.toml", "/ci/*"] +edition = "2018" + +[dependencies] +# For the default hasher +ahash = { version = "0.7.0", default-features = false, optional = true } + +# For external trait impls +rayon = { version = "1.0", optional = true } +serde = { version = "1.0.25", default-features = false, optional = true } + +# When built as part of libstd +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +compiler_builtins = { version = "0.1.2", optional = true } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } + +# Optional support for bumpalo +bumpalo = { version = "3.5.0", optional = true } + +[dev-dependencies] +lazy_static = "1.4" +rand = { version = "0.7.3", features = ["small_rng"] } +rayon = "1.0" +fnv = "1.0.7" +serde_test = "1.0" +doc-comment = "0.3.1" + +[features] +default = ["ahash", "inline-more"] + +ahash-compile-time-rng = ["ahash/compile-time-rng"] +nightly = [] +rustc-internal-api = [] +rustc-dep-of-std = [ + "nightly", + "core", + "compiler_builtins", + "alloc", + "rustc-internal-api", +] +raw = [] + +# Enables usage of `#[inline]` on far more functions than by default in this +# crate. This may lead to a performance increase but often comes at a compile +# time cost. +inline-more = [] + +[package.metadata.docs.rs] +features = ["nightly", "rayon", "serde", "raw"] diff --git a/third_party/rust/hashbrown/v0_11/crate/LICENSE-APACHE b/third_party/rust/hashbrown/v0_11/crate/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/hashbrown/v0_11/crate/LICENSE-MIT b/third_party/rust/hashbrown/v0_11/crate/LICENSE-MIT new file mode 100644 index 000000000000..5afc2a7b0aca --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Amanieu d'Antras + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/hashbrown/v0_11/crate/README.md b/third_party/rust/hashbrown/v0_11/crate/README.md new file mode 100644 index 000000000000..86664c4ce7bd --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/README.md @@ -0,0 +1,126 @@ +hashbrown +========= + +[![Build Status](https://travis-ci.com/rust-lang/hashbrown.svg?branch=master)](https://travis-ci.com/rust-lang/hashbrown) +[![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown) +[![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown) +[![Rust](https://img.shields.io/badge/rust-1.49.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown) + +This crate is a Rust port of Google's high-performance [SwissTable] hash +map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +and `HashSet` types. + +The original C++ version of SwissTable can be found [here], and this +[CppCon talk] gives an overview of how the algorithm works. + +Since Rust 1.36, this is now the `HashMap` implementation for the Rust standard +library. However you may still want to use this crate instead since it works +in environments without `std`, such as embedded systems and kernels. + +[SwissTable]: https://abseil.io/blog/20180927-swisstables +[here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +[CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +## [Change log](CHANGELOG.md) + +## Features + +- Drop-in replacement for the standard library `HashMap` and `HashSet` types. +- Uses [AHash](https://github.com/tkaitchuck/aHash) as the default hasher, which is much faster than SipHash. + However, AHash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher. +- Around 2x faster than the previous standard library `HashMap`. +- Lower memory usage: only 1 byte of overhead per entry instead of 8. +- Compatible with `#[no_std]` (but requires a global allocator with the `alloc` crate). +- Empty hash maps do not allocate any memory. +- SIMD lookups to scan multiple hash entries in parallel. + +## Performance + +Compared to the previous implementation of `std::collections::HashMap` (Rust 1.35). + +With the hashbrown default AHash hasher: + +| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +|:------------------------|:-------------------:|------------------:|:------------:|---------:|---------| +| insert_ahash_highbits | 18,865 | 8,020 | -10,845 | -57.49% | x 2.35 | +| insert_ahash_random | 19,711 | 8,019 | -11,692 | -59.32% | x 2.46 | +| insert_ahash_serial | 19,365 | 6,463 | -12,902 | -66.63% | x 3.00 | +| insert_erase_ahash_highbits | 51,136 | 17,916 | -33,220 | -64.96% | x 2.85 | +| insert_erase_ahash_random | 51,157 | 17,688 | -33,469 | -65.42% | x 2.89 | +| insert_erase_ahash_serial | 45,479 | 14,895 | -30,584 | -67.25% | x 3.05 | +| iter_ahash_highbits | 1,399 | 1,092 | -307 | -21.94% | x 1.28 | +| iter_ahash_random | 1,586 | 1,059 | -527 | -33.23% | x 1.50 | +| iter_ahash_serial | 3,168 | 1,079 | -2,089 | -65.94% | x 2.94 | +| lookup_ahash_highbits | 32,351 | 4,792 | -27,559 | -85.19% | x 6.75 | +| lookup_ahash_random | 17,419 | 4,817 | -12,602 | -72.35% | x 3.62 | +| lookup_ahash_serial | 15,254 | 3,606 | -11,648 | -76.36% | x 4.23 | +| lookup_fail_ahash_highbits | 21,187 | 4,369 | -16,818 | -79.38% | x 4.85 | +| lookup_fail_ahash_random | 21,550 | 4,395 | -17,155 | -79.61% | x 4.90 | +| lookup_fail_ahash_serial | 19,450 | 3,176 | -16,274 | -83.67% | x 6.12 | + + +With the libstd default SipHash hasher: + +|name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +|:------------------------|:-------------------:|------------------:|:------------:|---------:|---------| +|insert_std_highbits |19,216 |16,885 | -2,331 | -12.13% | x 1.14 | +|insert_std_random |19,179 |17,034 | -2,145 | -11.18% | x 1.13 | +|insert_std_serial |19,462 |17,493 | -1,969 | -10.12% | x 1.11 | +|insert_erase_std_highbits |50,825 |35,847 | -14,978 | -29.47% | x 1.42 | +|insert_erase_std_random |51,448 |35,392 | -16,056 | -31.21% | x 1.45 | +|insert_erase_std_serial |87,711 |38,091 | -49,620 | -56.57% | x 2.30 | +|iter_std_highbits |1,378 |1,159 | -219 | -15.89% | x 1.19 | +|iter_std_random |1,395 |1,132 | -263 | -18.85% | x 1.23 | +|iter_std_serial |1,704 |1,105 | -599 | -35.15% | x 1.54 | +|lookup_std_highbits |17,195 |13,642 | -3,553 | -20.66% | x 1.26 | +|lookup_std_random |17,181 |13,773 | -3,408 | -19.84% | x 1.25 | +|lookup_std_serial |15,483 |13,651 | -1,832 | -11.83% | x 1.13 | +|lookup_fail_std_highbits |20,926 |13,474 | -7,452 | -35.61% | x 1.55 | +|lookup_fail_std_random |21,766 |13,505 | -8,261 | -37.95% | x 1.61 | +|lookup_fail_std_serial |19,336 |13,519 | -5,817 | -30.08% | x 1.43 | + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +hashbrown = "0.11" +``` + +Then: + +```rust +use hashbrown::HashMap; + +let mut map = HashMap::new(); +map.insert(1, "one"); +``` +## Flags +This crate has the following Cargo features: + +- `nightly`: Enables nightly-only features including: `#[may_dangle]`. +- `serde`: Enables serde serialization support. +- `rayon`: Enables rayon parallel iterator support. +- `raw`: Enables access to the experimental and unsafe `RawTable` API. +- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost + of compilation time. (enabled by default) +- `bumpalo`: Provides a `BumpWrapper` type which allows `bumpalo` to be used for memory allocation. +- `ahash`: Compiles with ahash as default hasher. (enabled by default) +- `ahash-compile-time-rng`: Activates the `compile-time-rng` feature of ahash. For targets with no random number generator +this pre-generates seeds at compile time and embeds them as constants. See [aHash's documentation](https://github.com/tkaitchuck/aHash#flags) (disabled by default) + +## License + +Licensed under either of: + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/third_party/rust/hashbrown/v0_11/crate/benches/bench.rs b/third_party/rust/hashbrown/v0_11/crate/benches/bench.rs new file mode 100644 index 000000000000..568c513e10dc --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/benches/bench.rs @@ -0,0 +1,331 @@ +// This benchmark suite contains some benchmarks along a set of dimensions: +// Hasher: std default (SipHash) and crate default (AHash). +// Int key distribution: low bit heavy, top bit heavy, and random. +// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter +#![feature(test)] + +extern crate test; + +use test::{black_box, Bencher}; + +use hashbrown::hash_map::DefaultHashBuilder; +use hashbrown::{HashMap, HashSet}; +use std::{ + collections::hash_map::RandomState, + sync::atomic::{self, AtomicUsize}, +}; + +const SIZE: usize = 1000; + +// The default hashmap when using this crate directly. +type AHashMap = HashMap; +// This uses the hashmap from this crate with the default hasher of the stdlib. +type StdHashMap = HashMap; + +// A random key iterator. +#[derive(Clone, Copy)] +struct RandomKeys { + state: usize, +} + +impl RandomKeys { + fn new() -> Self { + RandomKeys { state: 0 } + } +} + +impl Iterator for RandomKeys { + type Item = usize; + fn next(&mut self) -> Option { + // Add 1 then multiply by some 32 bit prime. + self.state = self.state.wrapping_add(1).wrapping_mul(3787392781); + Some(self.state) + } +} + +// Just an arbitrary side effect to make the maps not shortcircuit to the non-dropping path +// when dropping maps/entries (most real world usages likely have drop in the key or value) +lazy_static::lazy_static! { + static ref SIDE_EFFECT: AtomicUsize = AtomicUsize::new(0); +} + +#[derive(Clone)] +struct DropType(usize); +impl Drop for DropType { + fn drop(&mut self) { + SIDE_EFFECT.fetch_add(self.0, atomic::Ordering::SeqCst); + } +} + +macro_rules! bench_suite { + ($bench_macro:ident, $bench_ahash_serial:ident, $bench_std_serial:ident, + $bench_ahash_highbits:ident, $bench_std_highbits:ident, + $bench_ahash_random:ident, $bench_std_random:ident) => { + $bench_macro!($bench_ahash_serial, AHashMap, 0..); + $bench_macro!($bench_std_serial, StdHashMap, 0..); + $bench_macro!( + $bench_ahash_highbits, + AHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!( + $bench_std_highbits, + StdHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!($bench_ahash_random, AHashMap, RandomKeys::new()); + $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new()); + }; +} + +macro_rules! bench_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default()); + b.iter(|| { + m.clear(); + for i in ($keydist).take(SIZE) { + m.insert(i, (DropType(i), [i; 20])); + } + black_box(&mut m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert, + insert_ahash_serial, + insert_std_serial, + insert_ahash_highbits, + insert_std_highbits, + insert_ahash_random, + insert_std_random +); + +macro_rules! bench_grow_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + black_box(&mut m); + }) + } + }; +} + +bench_suite!( + bench_grow_insert, + grow_insert_ahash_serial, + grow_insert_std_serial, + grow_insert_ahash_highbits, + grow_insert_std_highbits, + grow_insert_ahash_random, + grow_insert_std_random +); + +macro_rules! bench_insert_erase { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut base = $maptype::default(); + for i in ($keydist).take(SIZE) { + base.insert(i, DropType(i)); + } + let skip = $keydist.skip(SIZE); + b.iter(|| { + let mut m = base.clone(); + let mut add_iter = skip.clone(); + let mut remove_iter = $keydist; + // While keeping the size constant, + // replace the first keydist with the second. + for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) { + m.insert(add, DropType(add)); + black_box(m.remove(&remove)); + } + black_box(m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert_erase, + insert_erase_ahash_serial, + insert_erase_std_serial, + insert_erase_ahash_highbits, + insert_erase_std_highbits, + insert_erase_ahash_random, + insert_erase_std_random +); + +macro_rules! bench_lookup { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in $keydist.take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in $keydist.take(SIZE) { + black_box(m.get(&i)); + } + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_lookup, + lookup_ahash_serial, + lookup_std_serial, + lookup_ahash_highbits, + lookup_std_highbits, + lookup_ahash_random, + lookup_std_random +); + +macro_rules! bench_lookup_fail { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + let mut iter = $keydist; + for i in (&mut iter).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in (&mut iter).take(SIZE) { + black_box(m.get(&i)); + } + }) + } + }; +} + +bench_suite!( + bench_lookup_fail, + lookup_fail_ahash_serial, + lookup_fail_std_serial, + lookup_fail_ahash_highbits, + lookup_fail_std_highbits, + lookup_fail_ahash_random, + lookup_fail_std_random +); + +macro_rules! bench_iter { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in &m { + black_box(i); + } + }) + } + }; +} + +bench_suite!( + bench_iter, + iter_ahash_serial, + iter_std_serial, + iter_ahash_highbits, + iter_std_highbits, + iter_ahash_random, + iter_std_random +); + +#[bench] +fn clone_small(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_small(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn clone_large(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_large(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn rehash_in_place(b: &mut Bencher) { + b.iter(|| { + let mut set = HashSet::new(); + + // Each loop triggers one rehash + for _ in 0..10 { + for i in 0..224 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + set.clear(); + } + }); +} diff --git a/third_party/rust/hashbrown/v0_11/crate/clippy.toml b/third_party/rust/hashbrown/v0_11/crate/clippy.toml new file mode 100644 index 000000000000..d98bf2c09b13 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/clippy.toml @@ -0,0 +1 @@ +doc-valid-idents = [ "CppCon", "SwissTable", "SipHash", "HashDoS" ] diff --git a/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/mod.rs b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/mod.rs new file mode 100644 index 000000000000..ef497836cb98 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/mod.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "rayon")] +pub(crate) mod rayon; +#[cfg(feature = "serde")] +mod serde; diff --git a/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/helpers.rs b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/helpers.rs new file mode 100644 index 000000000000..9382007ea25b --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/helpers.rs @@ -0,0 +1,26 @@ +use alloc::collections::LinkedList; +use alloc::vec::Vec; + +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Helper for collecting parallel iterators to an intermediary +pub(super) fn collect(iter: I) -> (LinkedList>, usize) { + let list = iter + .into_par_iter() + .fold(Vec::new, |mut vec, elem| { + vec.push(elem); + vec + }) + .map(|vec| { + let mut list = LinkedList::new(); + list.push_back(vec); + list + }) + .reduce(LinkedList::new, |mut list1, mut list2| { + list1.append(&mut list2); + list1 + }); + + let len = list.iter().map(Vec::len).sum(); + (list, len) +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/map.rs b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/map.rs new file mode 100644 index 000000000000..61b73806114b --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/map.rs @@ -0,0 +1,734 @@ +//! Rayon extensions for `HashMap`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_map::HashMap; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to keys in a map. +/// +/// This iterator is created by the [`par_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParKeys<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().0 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParKeys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParKeys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to values in a map. +/// +/// This iterator is created by the [`par_values`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValues<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().1 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParValues<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParValues<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_mut(); + (&r.0, &mut r.1) + }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over mutable references to values in a map. +/// +/// This iterator is created by the [`par_values_mut`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValuesMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &mut x.as_mut().1 }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParValues { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter<(K, V), A>, +} + +impl ParallelIterator for IntoParIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug + for IntoParIter +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParDrain<'a, K, V, A: Allocator + Clone = Global> { + inner: RawParDrain<'a, (K, V), A>, +} + +impl ParallelIterator for ParDrain<'_, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug + for ParDrain<'_, K, V, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashMap { + /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl HashMap { + /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> { + ParDrain { + inner: self.table.par_drain(), + } + } +} + +impl HashMap +where + K: Eq + Hash + Sync, + V: PartialEq + Sync, + S: BuildHasher + Sync, + A: Allocator + Clone + Sync, +{ + /// Returns `true` if the map is equal to another, + /// i.e. both maps contain the same keys mapped to the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() + && self + .into_par_iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl IntoParallelIterator + for HashMap +{ + type Item = (K, V); + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.table.into_par_iter(), + } + } +} + +impl<'a, K: Sync, V: Sync, S, A: Allocator + Clone> IntoParallelIterator + for &'a HashMap +{ + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, K: Sync, V: Send, S, A: Allocator + Clone> IntoParallelIterator + for &'a mut HashMap +{ + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +/// Collect (key, value) pairs from a parallel iterator into a +/// hashmap. If multiple pairs correspond to the same key, then the +/// ones produced earlier in the parallel iterator will be +/// overwritten, just as with a sequential iterator. +impl FromParallelIterator<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut map = HashMap::default(); + map.par_extend(par_iter); + map + } +} + +/// Extend a hash map with items from a parallel iterator. +impl ParallelExtend<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher, + A: Allocator + Clone, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash map with copied items from a parallel iterator. +impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap +where + K: Copy + Eq + Hash + Sync, + V: Copy + Sync, + S: BuildHasher, + A: Allocator + Clone, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashMap` -- no custom advantage. +fn extend(map: &mut HashMap, par_iter: I) +where + K: Eq + Hash, + S: BuildHasher, + I: IntoParallelIterator, + A: Allocator + Clone, + HashMap: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire length if the map is empty. + // Otherwise reserve half the length (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if map.is_empty() { len } else { (len + 1) / 2 }; + map.reserve(reserve); + for vec in list { + map.extend(vec); + } +} + +#[cfg(test)] +mod test_par_map { + use alloc::vec::Vec; + use core::hash::{Hash, Hasher}; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_map::HashMap; + + struct Dropable<'a> { + k: usize, + counter: &'a AtomicUsize, + } + + impl Dropable<'_> { + fn new(k: usize, counter: &AtomicUsize) -> Dropable<'_> { + counter.fetch_add(1, Ordering::Relaxed); + + Dropable { k, counter } + } + } + + impl Drop for Dropable<'_> { + fn drop(&mut self) { + self.counter.fetch_sub(1, Ordering::Relaxed); + } + } + + impl Clone for Dropable<'_> { + fn clone(&self) -> Self { + Dropable::new(self.k, self.counter) + } + } + + impl Hash for Dropable<'_> { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.k.hash(state) + } + } + + impl PartialEq for Dropable<'_> { + fn eq(&self, other: &Self) -> bool { + self.k == other.k + } + } + + impl Eq for Dropable<'_> {} + + #[test] + fn test_into_iter_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Dropable::new(i, &key); + let d2 = Dropable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the iterator does not leak anything. + drop(hm.clone().into_par_iter()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm + .into_par_iter() + .filter(|&(ref key, _)| key.k < 50) + .collect(); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_drain_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let mut hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Dropable::new(i, &key); + let d2 = Dropable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the drain iterator does not leak anything. + drop(hm.clone().par_drain()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.drain().filter(|&(ref key, _)| key.k < 50).collect(); + assert!(hm.is_empty()); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.par_drain().count(), 0); + assert_eq!(m.par_keys().count(), 0); + assert_eq!(m.par_values().count(), 0); + assert_eq!(m.par_values_mut().count(), 0); + assert_eq!(m.par_iter().count(), 0); + assert_eq!(m.par_iter_mut().count(), 0); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_par_iter().count(), 0); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let observed = AtomicUsize::new(0); + + m.par_iter().for_each(|(k, v)| { + assert_eq!(*v, *k * 2); + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let keys: Vec<_> = map.par_keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_par_iter().collect(); + map.par_values_mut().for_each(|value| *value = (*value) * 2); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(!m1.par_eq(&m2)); + + m2.insert(3, 4); + + assert!(m1.par_eq(&m2)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.par_iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + } + + #[test] + fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.par_extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/mod.rs b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/mod.rs new file mode 100644 index 000000000000..99337a1ce386 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/mod.rs @@ -0,0 +1,4 @@ +mod helpers; +pub(crate) mod map; +pub(crate) mod raw; +pub(crate) mod set; diff --git a/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/raw.rs b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/raw.rs new file mode 100644 index 000000000000..18da1eacdc37 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/raw.rs @@ -0,0 +1,229 @@ +use crate::raw::Bucket; +use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable}; +use crate::scopeguard::guard; +use alloc::alloc::dealloc; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; +use rayon::iter::{ + plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer}, + ParallelIterator, +}; + +/// Parallel iterator which returns a raw pointer to every full bucket in the table. +pub struct RawParIter { + iter: RawIterRange, +} + +impl RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn iter(&self) -> RawIterRange { + self.iter.clone() + } +} + +impl Clone for RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + } + } +} + +impl From> for RawParIter { + fn from(it: RawIter) -> Self { + RawParIter { iter: it.iter } + } +} + +impl ParallelIterator for RawParIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let producer = ParIterProducer { iter: self.iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Producer which returns a `Bucket` for every element. +struct ParIterProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParIterProducer { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.split(); + let left = ParIterProducer { iter: left }; + let right = right.map(|right| ParIterProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(self, folder: F) -> F + where + F: Folder, + { + folder.consume_iter(self.iter) + } +} + +/// Parallel iterator which consumes a table and returns elements. +pub struct RawIntoParIter { + table: RawTable, +} + +impl RawIntoParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.par_iter() + } +} + +impl ParallelIterator for RawIntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let iter = unsafe { self.table.iter().iter }; + let _guard = guard(self.table.into_allocation(), |alloc| { + if let Some((ptr, layout)) = *alloc { + unsafe { + dealloc(ptr.as_ptr(), layout); + } + } + }); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Parallel iterator which consumes elements without freeing the table storage. +pub struct RawParDrain<'a, T, A: Allocator + Clone = Global> { + // We don't use a &'a mut RawTable because we want RawParDrain to be + // covariant over T. + table: NonNull>, + marker: PhantomData<&'a RawTable>, +} + +unsafe impl Send for RawParDrain<'_, T, A> {} + +impl RawParDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.as_ref().par_iter() + } +} + +impl ParallelIterator for RawParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let _guard = guard(self.table, |table| unsafe { + table.as_mut().clear_no_drop() + }); + let iter = unsafe { self.table.as_ref().iter().iter }; + mem::forget(self); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +impl Drop for RawParDrain<'_, T, A> { + fn drop(&mut self) { + // If drive_unindexed is not called then simply clear the table. + unsafe { self.table.as_mut().clear() } + } +} + +/// Producer which will consume all elements in the range, even if it is dropped +/// halfway through. +struct ParDrainProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParDrainProducer { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.clone().split(); + mem::forget(self); + let left = ParDrainProducer { iter: left }; + let right = right.map(|right| ParDrainProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(mut self, mut folder: F) -> F + where + F: Folder, + { + // Make sure to modify the iterator in-place so that any remaining + // elements are processed in our Drop impl. + while let Some(item) = self.iter.next() { + folder = folder.consume(unsafe { item.read() }); + if folder.full() { + return folder; + } + } + + // If we processed all elements then we don't need to run the drop. + mem::forget(self); + folder + } +} + +impl Drop for ParDrainProducer { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + // Drop all remaining elements + if mem::needs_drop::() { + while let Some(item) = self.iter.next() { + unsafe { + item.drop(); + } + } + } + } +} + +impl RawTable { + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn par_iter(&self) -> RawParIter { + RawParIter { + iter: self.iter().iter, + } + } + + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_par_iter(self) -> RawIntoParIter { + RawIntoParIter { table: self } + } + + /// Returns a parallel iterator which consumes all elements of a `RawTable` + /// without freeing its memory allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> RawParDrain<'_, T, A> { + RawParDrain { + table: NonNull::from(self), + marker: PhantomData, + } + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/set.rs b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/set.rs new file mode 100644 index 000000000000..ee4f6e66931b --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/rayon/set.rs @@ -0,0 +1,659 @@ +//! Rayon extensions for `HashSet`. + +use super::map; +use crate::hash_set::HashSet; +use crate::raw::{Allocator, Global}; +use core::hash::{BuildHasher, Hash}; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over elements of a consumed set. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: map::IntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel draining iterator over entries of a set. +/// +/// This iterator is created by the [`par_drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashSet.html#method.par_drain +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDrain<'a, T, A: Allocator + Clone = Global> { + inner: map::ParDrain<'a, T, (), A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in a set. +/// +/// This iterator is created by the [`par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: map::ParKeys<'a, T, ()>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the difference of +/// sets. +/// +/// This iterator is created by the [`par_difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDifference<'a, T, S, A: Allocator + Clone = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Clone + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| !self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the symmetric +/// difference of sets. +/// +/// This iterator is created by the [`par_symmetric_difference`] method on +/// [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParSymmetricDifference<'a, T, S, A: Allocator + Clone = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Clone + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .par_difference(self.b) + .chain(self.b.par_difference(self.a)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the intersection of +/// sets. +/// +/// This iterator is created by the [`par_intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParIntersection<'a, T, S, A: Allocator + Clone = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Clone + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the union of sets. +/// +/// This iterator is created by the [`par_union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParUnion<'a, T, S, A: Allocator + Clone = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Clone + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.a.len() <= self.b.len() { + (self.a, self.b) + } else { + (self.b, self.a) + }; + larger + .into_par_iter() + .chain(smaller.par_difference(larger)) + .drive_unindexed(consumer) + } +} + +impl HashSet +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Clone + Sync, +{ + /// Visits (potentially in parallel) the values representing the union, + /// i.e. all the values in `self` or `other`, without duplicates. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> { + ParUnion { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the difference, + /// i.e. the values that are in `self` but not in `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_difference<'a>(&'a self, other: &'a Self) -> ParDifference<'a, T, S, A> { + ParDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the symmetric + /// difference, i.e. the values that are in `self` or in `other` but not in both. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_symmetric_difference<'a>( + &'a self, + other: &'a Self, + ) -> ParSymmetricDifference<'a, T, S, A> { + ParSymmetricDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the + /// intersection, i.e. the values that are both in `self` and `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_intersection<'a>(&'a self, other: &'a Self) -> ParIntersection<'a, T, S, A> { + ParIntersection { a: self, b: other } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_disjoint(&self, other: &Self) -> bool { + self.into_par_iter().all(|x| !other.contains(x)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e. `other` contains at least all the values in `self`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_subset(&self, other: &Self) -> bool { + if self.len() <= other.len() { + self.into_par_iter().all(|x| other.contains(x)) + } else { + false + } + } + + /// Returns `true` if the set is a superset of another, + /// i.e. `self` contains at least all the values in `other`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_superset(&self, other: &Self) -> bool { + other.par_is_subset(self) + } + + /// Returns `true` if the set is equal to another, + /// i.e. both sets contain the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.par_is_subset(other) + } +} + +impl HashSet +where + T: Eq + Hash + Send, + A: Allocator + Clone + Send, +{ + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the set's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.map.par_drain(), + } + } +} + +impl IntoParallelIterator for HashSet { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.map.into_par_iter(), + } + } +} + +impl<'a, T: Sync, S, A: Allocator + Clone> IntoParallelIterator for &'a HashSet { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: self.map.par_keys(), + } + } +} + +/// Collect values from a parallel iterator into a hashset. +impl FromParallelIterator for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut set = HashSet::default(); + set.par_extend(par_iter); + set + } +} + +/// Extend a hash set with items from a parallel iterator. +impl ParallelExtend for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash set with copied items from a parallel iterator. +impl<'a, T, S> ParallelExtend<&'a T> for HashSet +where + T: 'a + Copy + Eq + Hash + Sync, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashSet` -- no custom advantage. +fn extend(set: &mut HashSet, par_iter: I) +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, + I: IntoParallelIterator, + HashSet: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Values may be already present or show multiple times in the iterator. + // Reserve the entire length if the set is empty. + // Otherwise reserve half the length (rounded up), so the set + // will only resize twice in the worst case. + let reserve = if set.is_empty() { len } else { (len + 1) / 2 }; + set.reserve(reserve); + for vec in list { + set.extend(vec); + } +} + +#[cfg(test)] +mod test_par_set { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_set::HashSet; + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.par_is_disjoint(&ys)); + assert!(!ys.par_is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(!b.par_is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(b.par_is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let i = a + .par_intersection(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let expected = [1, 5, 11]; + let i = a + .par_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let expected = [-2, 1, 5, 11, 14, 22]; + let i = a + .par_symmetric_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + let i = a + .par_union(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.par_iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(!s1.par_eq(&s2)); + + s2.insert(3); + + assert!(s1.par_eq(&s2)); + } + + #[test] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.par_extend(&[2, 3, 4][..]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.par_extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/serde.rs b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/serde.rs new file mode 100644 index 000000000000..7816e780395b --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/external_trait_impls/serde.rs @@ -0,0 +1,200 @@ +mod size_hint { + use core::cmp; + + /// This presumably exists to prevent denial of service attacks. + /// + /// Original discussion: https://github.com/serde-rs/serde/issues/1114. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn cautious(hint: Option) -> usize { + cmp::min(hint.unwrap_or(0), 4096) + } +} + +mod map { + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, MapAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_map::HashMap; + + use super::size_hint; + + impl Serialize for HashMap + where + K: Serialize + Eq + Hash, + V: Serialize, + H: BuildHasher, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_map(self) + } + } + + impl<'de, K, V, S> Deserialize<'de> for HashMap + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor { + marker: PhantomData>, + } + + impl<'de, K, V, S> Visitor<'de> for MapVisitor + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + { + type Value = HashMap; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut values = HashMap::with_capacity_and_hasher( + size_hint::cautious(map.size_hint()), + S::default(), + ); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { + marker: PhantomData, + }; + deserializer.deserialize_map(visitor) + } + } +} + +mod set { + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_set::HashSet; + + use super::size_hint; + + impl Serialize for HashSet + where + T: Serialize + Eq + Hash, + H: BuildHasher, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + + impl<'de, T, S> Deserialize<'de> for HashSet + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SeqVisitor { + marker: PhantomData>, + } + + impl<'de, T, S> Visitor<'de> for SeqVisitor + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + { + type Value = HashSet; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut values = HashSet::with_capacity_and_hasher( + size_hint::cautious(seq.size_hint()), + S::default(), + ); + + while let Some(value) = seq.next_element()? { + values.insert(value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T, S>(&'a mut HashSet); + + impl<'a, 'de, T, S> Visitor<'de> for SeqInPlaceVisitor<'a, T, S> + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + self.0.clear(); + self.0.reserve(size_hint::cautious(seq.size_hint())); + + while let Some(value) = seq.next_element()? { + self.0.insert(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/lib.rs b/third_party/rust/hashbrown/v0_11/crate/src/lib.rs new file mode 100644 index 000000000000..b2d6584ff319 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/lib.rs @@ -0,0 +1,161 @@ +//! This crate is a Rust port of Google's high-performance [SwissTable] hash +//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +//! and `HashSet` types. +//! +//! The original C++ version of [SwissTable] can be found [here], and this +//! [CppCon talk] gives an overview of how the algorithm works. +//! +//! [SwissTable]: https://abseil.io/blog/20180927-swisstables +//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +#![no_std] +#![cfg_attr( + feature = "nightly", + feature( + test, + core_intrinsics, + dropck_eyepatch, + min_specialization, + extend_one, + allocator_api, + slice_ptr_get, + nonnull_slice_from_raw_parts, + maybe_uninit_array_assume_init + ) +)] +#![allow( + clippy::doc_markdown, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::option_if_let_else, + clippy::redundant_else, + clippy::manual_map +)] +#![warn(missing_docs)] +#![warn(rust_2018_idioms)] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg_attr(test, macro_use)] +extern crate alloc; + +#[cfg(feature = "nightly")] +#[cfg(doctest)] +doc_comment::doctest!("../README.md"); + +#[macro_use] +mod macros; + +#[cfg(feature = "raw")] +/// Experimental and unsafe `RawTable` API. This module is only available if the +/// `raw` feature is enabled. +pub mod raw { + // The RawTable API is still experimental and is not properly documented yet. + #[allow(missing_docs)] + #[path = "mod.rs"] + mod inner; + pub use inner::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::raw::*; + } +} +#[cfg(not(feature = "raw"))] +mod raw; + +mod external_trait_impls; +mod map; +#[cfg(feature = "rustc-internal-api")] +mod rustc_entry; +mod scopeguard; +mod set; + +pub mod hash_map { + //! A hash map implemented with quadratic probing and SIMD lookup. + pub use crate::map::*; + + #[cfg(feature = "rustc-internal-api")] + pub use crate::rustc_entry::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::map::*; + } +} +pub mod hash_set { + //! A hash set implemented as a `HashMap` where the value is `()`. + pub use crate::set::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash sets. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::set::*; + } +} + +pub use crate::map::HashMap; +pub use crate::set::HashSet; + +/// The error type for `try_reserve` methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TryReserveError { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + + /// The memory allocator returned an error + AllocError { + /// The layout of the allocation request that failed. + layout: alloc::alloc::Layout, + }, +} + +/// The error type for [`RawTable::get_each_mut`](crate::raw::RawTable::get_each_mut), +/// [`HashMap::get_each_mut`], and [`HashMap::get_each_key_value_mut`]. +#[cfg(feature = "nightly")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum UnavailableMutError { + /// The requested entry is not present in the table. + Absent, + /// The requested entry is present, but a mutable reference to it was already created and + /// returned from this call to `get_each_mut` or `get_each_key_value_mut`. + /// + /// Includes the index of the existing mutable reference in the returned array. + Duplicate(usize), +} + +/// Wrapper around `Bump` which allows it to be used as an allocator for +/// `HashMap`, `HashSet` and `RawTable`. +/// +/// `Bump` can be used directly without this wrapper on nightly if you enable +/// the `allocator-api` feature of the `bumpalo` crate. +#[cfg(feature = "bumpalo")] +#[derive(Clone, Copy, Debug)] +pub struct BumpWrapper<'a>(pub &'a bumpalo::Bump); + +#[cfg(feature = "bumpalo")] +#[test] +fn test_bumpalo() { + use bumpalo::Bump; + let bump = Bump::new(); + let mut map = HashMap::new_in(BumpWrapper(&bump)); + map.insert(0, 1); +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/macros.rs b/third_party/rust/hashbrown/v0_11/crate/src/macros.rs new file mode 100644 index 000000000000..027959731356 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/macros.rs @@ -0,0 +1,69 @@ +// See the cfg-if crate. +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an approprate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +// Helper macro for specialization. This also helps avoid parse errors if the +// default fn syntax for specialization changes in the future. +#[cfg(feature = "nightly")] +macro_rules! default_fn { + ($($tt:tt)*) => { + default $($tt)* + } +} +#[cfg(not(feature = "nightly"))] +macro_rules! default_fn { + ($($tt:tt)*) => { + $($tt)* + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/map.rs b/third_party/rust/hashbrown/v0_11/crate/src/map.rs new file mode 100644 index 000000000000..ab1128879f1b --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/map.rs @@ -0,0 +1,4922 @@ +use crate::raw::{Allocator, Bucket, Global, RawDrain, RawIntoIter, RawIter, RawTable}; +use crate::TryReserveError; +#[cfg(feature = "nightly")] +use crate::UnavailableMutError; +use core::borrow::Borrow; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::iter::{FromIterator, FusedIterator}; +use core::marker::PhantomData; +use core::mem; +#[cfg(feature = "nightly")] +use core::mem::MaybeUninit; +use core::ops::Index; + +/// Default hasher for `HashMap`. +#[cfg(feature = "ahash")] +pub type DefaultHashBuilder = ahash::RandomState; + +/// Dummy default hasher for `HashMap`. +#[cfg(not(feature = "ahash"))] +pub enum DefaultHashBuilder {} + +/// A hash map implemented with quadratic probing and SIMD lookup. +/// +/// The default hashing algorithm is currently [`AHash`], though this is +/// subject to change at any point in the future. This hash function is very +/// fast for all types of keys, but this algorithm will typically *not* protect +/// against attacks such as HashDoS. +/// +/// The hashing algorithm can be replaced on a per-`HashMap` basis using the +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many +/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. +/// +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although +/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. +/// If you implement these yourself, it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// It is a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashMap` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); +/// +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). +/// if !book_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove("The Adventures of Sherlock Holmes"); +/// +/// // Look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for &book in &to_find { +/// match book_reviews.get(book) { +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) +/// } +/// } +/// +/// // Look up the value for a key (will panic if the key is not found). +/// println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]); +/// +/// // Iterate over everything. +/// for (book, review) in &book_reviews { +/// println!("{}: \"{}\"", book, review); +/// } +/// ``` +/// +/// `HashMap` also implements an [`Entry API`](#method.entry), which allows +/// for more complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, u8>` in this example). +/// let mut player_stats = HashMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// ``` +/// +/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`default`]: #method.default +/// [`with_hasher`]: #method.with_hasher +/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher +/// [`fnv`]: https://crates.io/crates/fnv +/// [`AHash`]: https://crates.io/crates/ahash +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// country: String, +/// } +/// +/// impl Viking { +/// /// Creates a new Viking. +/// fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. +/// let mut vikings = HashMap::new(); +/// +/// vikings.insert(Viking::new("Einar", "Norway"), 25); +/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); +/// vikings.insert(Viking::new("Harald", "Iceland"), 12); +/// +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in &vikings { +/// println!("{:?} has {} hp", viking, health); +/// } +/// ``` +/// +/// A `HashMap` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] +/// .iter().cloned().collect(); +/// // use the values stored in map +/// ``` +pub struct HashMap { + pub(crate) hash_builder: S, + pub(crate) table: RawTable<(K, V), A>, +} + +impl Clone for HashMap { + fn clone(&self) -> Self { + HashMap { + hash_builder: self.hash_builder.clone(), + table: self.table.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.table.clone_from(&source.table); + + // Update hash_builder only if we successfully cloned all elements. + self.hash_builder.clone_from(&source.hash_builder); + } +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hasher(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ +where + K: Borrow, + Q: Hash, + S: BuildHasher, +{ + move |val| make_hash::(hash_builder, &val.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +fn equivalent_key(k: &Q) -> impl Fn(&(K, V)) -> bool + '_ +where + K: Borrow, + Q: ?Sized + Eq, +{ + move |x| k.eq(x.0.borrow()) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +fn equivalent(k: &Q) -> impl Fn(&K) -> bool + '_ +where + K: Borrow, + Q: ?Sized + Eq, +{ + move |x| k.eq(x.borrow()) +} + +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + K: Borrow, + Q: Hash + ?Sized, + S: BuildHasher, +{ + use core::hash::Hasher; + let mut state = hash_builder.build_hasher(); + val.hash(&mut state); + state.finish() +} + +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_insert_hash(hash_builder: &S, val: &K) -> u64 +where + K: Hash, + S: BuildHasher, +{ + use core::hash::Hasher; + let mut state = hash_builder.build_hasher(); + val.hash(&mut state); + state.finish() +} + +#[cfg(feature = "ahash")] +impl HashMap { + /// Creates an empty `HashMap`. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self::default() + } + + /// Creates an empty `HashMap` with the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_and_hasher(capacity, DefaultHashBuilder::default()) + } +} + +#[cfg(feature = "ahash")] +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self::with_hasher_in(DefaultHashBuilder::default(), alloc) + } + + /// Creates an empty `HashMap` with the specified capacity using the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self::with_capacity_and_hasher_in(capacity, DefaultHashBuilder::default(), alloc) + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::new(), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity(capacity), + } + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. It will be allocated with the given allocator. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. It will be allocated with the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = map.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the `HashMap` might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map: HashMap = HashMap::with_capacity(100); + /// assert!(map.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.table.capacity() + } + + /// An iterator visiting all keys in arbitrary order. + /// The iterator element type is `&'a K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for key in map.keys() { + /// println!("{}", key); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { inner: self.iter() } + } + + /// An iterator visiting all values in arbitrary order. + /// The iterator element type is `&'a V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for val in map.values() { + /// println!("{}", val); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values(&self) -> Values<'_, K, V> { + Values { inner: self.iter() } + } + + /// An iterator visiting all values mutably in arbitrary order. + /// The iterator element type is `&'a mut V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for val in map.values_mut() { + /// *val = *val + 10; + /// } + /// + /// for val in map.values() { + /// println!("{}", val); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut { + inner: self.iter_mut(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + Iter { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// The iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// for (key, val) in &map { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + IterMut { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + #[cfg(test)] + #[cfg_attr(feature = "inline-more", inline)] + fn raw_capacity(&self) -> usize { + self.table.buckets() + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.table.len() + } + + /// Returns `true` if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// for (k, v) in a.drain().take(1) { + /// assert!(k == 1 || k == 2); + /// assert!(v == "a" || v == "b"); + /// } + /// + /// assert!(a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, K, V, A> { + Drain { + inner: self.table.drain(), + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// map.retain(|&k, _| k % 2 == 0); + /// assert_eq!(map.len(), 4); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.table.iter() { + let &mut (ref key, ref mut value) = item.as_mut(); + if !f(key, value) { + self.table.erase(item); + } + } + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all pairs `(k, v)` such that `f(&k,&mut v)` returns `true` out + /// into another iterator. + /// + /// When the returned DrainedFilter is dropped, any remaining elements that satisfy + /// the predicate are dropped from the table. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().cloned().collect::>(); + /// let mut odds = map.keys().cloned().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, K, V, F, A> + where + F: FnMut(&K, &mut V) -> bool, + { + DrainFilter { + f, + inner: DrainFilterInner { + iter: unsafe { self.table.iter() }, + table: &mut self.table, + }, + } + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.clear(); + /// assert!(a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.table.clear(); + } +} + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows [`usize`]. + /// + /// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// map.reserve(10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.table + .reserve(additional, make_hasher::(&self.hash_builder)); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.table + .try_reserve(additional, make_hasher::(&self.hash_builder)) + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.table + .shrink_to(0, make_hasher::(&self.hash_builder)); + } + + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// This function does nothing if the current capacity is smaller than the + /// supplied minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.table + .shrink_to(min_capacity, make_hasher::(&self.hash_builder)); + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> { + let hash = make_insert_hash::(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, equivalent_key(&key)) { + Entry::Occupied(OccupiedEntry { + hash, + key: Some(key), + elem, + table: self, + }) + } else { + Entry::Vacant(VacantEntry { + hash, + key, + table: self, + }) + } + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + Q: Hash + Eq, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some(&(_, ref v)) => Some(v), + None => None, + } + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[inline] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + K: Borrow, + Q: Hash + Eq, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some(&(ref key, ref value)) => Some((key, value)), + None => None, + } + } + + #[inline] + fn get_inner(&self, k: &Q) -> Option<&(K, V)> + where + K: Borrow, + Q: Hash + Eq, + { + let hash = make_hash::(&self.hash_builder, k); + self.table.get(hash, equivalent_key(k)) + } + + /// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// let (k, v) = map.get_key_value_mut(&1).unwrap(); + /// assert_eq!(k, &1); + /// assert_eq!(v, &mut "a"); + /// *v = "b"; + /// assert_eq!(map.get_key_value_mut(&1), Some((&1, &mut "b"))); + /// assert_eq!(map.get_key_value_mut(&2), None); + /// ``` + #[inline] + pub fn get_key_value_mut(&mut self, k: &Q) -> Option<(&K, &mut V)> + where + K: Borrow, + Q: Hash + Eq, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (ref key, ref mut value)) => Some((key, value)), + None => None, + } + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains_key(&self, k: &Q) -> bool + where + K: Borrow, + Q: Hash + Eq, + { + self.get_inner(k).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + Q: Hash + Eq, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (_, ref mut v)) => Some(v), + None => None, + } + } + + #[inline] + fn get_inner_mut(&mut self, k: &Q) -> Option<&mut (K, V)> + where + K: Borrow, + Q: Hash + Eq, + { + let hash = make_hash::(&self.hash_builder, k); + self.table.get_mut(hash, equivalent_key(k)) + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, + /// at most one mutable reference will be returned to any value. An + /// `Err(UnavailableMutError::Duplicate(i))` in the returned array indicates that a suitable + /// key-value pair exists, but a mutable reference to the value already occurs at index `i` in + /// the returned array. + /// + /// This method is available only if the `nightly` feature is enabled. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{HashMap, UnavailableMutError}; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_each_mut([ + /// "Athenæum", + /// "New York Public Library", + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Ok(&mut 1807), + /// Err(UnavailableMutError::Absent), + /// Err(UnavailableMutError::Duplicate(0)), + /// Ok(&mut 1800), + /// ] + /// ); + /// ``` + #[cfg(feature = "nightly")] + pub fn get_each_mut( + &mut self, + ks: [&Q; N], + ) -> [Result<&'_ mut V, UnavailableMutError>; N] + where + K: Borrow, + Q: Hash + Eq, + { + let mut pairs = self.get_each_inner_mut(ks); + // TODO use `MaybeUninit::uninit_array` here instead once that's stable. + let mut out: [MaybeUninit>; N] = + unsafe { MaybeUninit::uninit().assume_init() }; + for i in 0..N { + out[i] = MaybeUninit::new( + mem::replace(&mut pairs[i], Err(UnavailableMutError::Absent)).map(|(_, v)| v), + ); + } + unsafe { MaybeUninit::array_assume_init(out) } + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys. + /// + /// Returns an array of length `N` with the results of each query. For soundness, + /// at most one mutable reference will be returned to any value. An + /// `Err(UnavailableMutError::Duplicate(i))` in the returned array indicates that a suitable + /// key-value pair exists, but a mutable reference to the value already occurs at index `i` in + /// the returned array. + /// + /// This method is available only if the `nightly` feature is enabled. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{HashMap, UnavailableMutError}; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_each_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// "Gewandhaus", + /// ]); + /// assert_eq!( + /// got, + /// [ + /// Ok((&"Bodleian Library".to_string(), &mut 1602)), + /// Ok((&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691)), + /// Err(UnavailableMutError::Duplicate(1)), + /// Err(UnavailableMutError::Absent), + /// ] + /// ); + /// ``` + #[cfg(feature = "nightly")] + pub fn get_each_key_value_mut( + &mut self, + ks: [&Q; N], + ) -> [Result<(&'_ K, &'_ mut V), UnavailableMutError>; N] + where + K: Borrow, + Q: Hash + Eq, + { + let mut pairs = self.get_each_inner_mut(ks); + // TODO use `MaybeUninit::uninit_array` here instead once that's stable. + let mut out: [MaybeUninit>; N] = + unsafe { MaybeUninit::uninit().assume_init() }; + for i in 0..N { + out[i] = MaybeUninit::new( + mem::replace(&mut pairs[i], Err(UnavailableMutError::Absent)) + .map(|(k, v)| (&*k, v)), + ); + } + unsafe { MaybeUninit::array_assume_init(out) } + } + + #[cfg(feature = "nightly")] + fn get_each_inner_mut( + &mut self, + ks: [&Q; N], + ) -> [Result<&'_ mut (K, V), UnavailableMutError>; N] + where + K: Borrow, + Q: Hash + Eq, + { + let mut hashes = [0_u64; N]; + for i in 0..N { + hashes[i] = make_hash::(&self.hash_builder, ks[i]); + } + self.table + .get_each_mut(hashes, |i, (k, _)| ks[i].eq(k.borrow())) + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. + /// + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// [module-level documentation]: index.html#insert-and-complex-keys + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, k: K, v: V) -> Option { + let hash = make_insert_hash::(&self.hash_builder, &k); + if let Some((_, item)) = self.table.get_mut(hash, equivalent_key(&k)) { + Some(mem::replace(item, v)) + } else { + self.table + .insert(hash, (k, v), make_hasher::(&self.hash_builder)); + None + } + } + + /// Tries to insert a key-value pair into the map, and returns + /// a mutable reference to the value in the entry. + /// + /// # Errors + /// + /// If the map already had this key present, nothing is updated, and + /// an error containing the occupied entry and the value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a"); + /// + /// let err = map.try_insert(37, "b").unwrap_err(); + /// assert_eq!(err.entry.key(), &37); + /// assert_eq!(err.entry.get(), &"a"); + /// assert_eq!(err.value, "b"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert( + &mut self, + key: K, + value: V, + ) -> Result<&mut V, OccupiedError<'_, K, V, S, A>> { + match self.entry(key) { + Entry::Occupied(entry) => Err(OccupiedError { entry, value }), + Entry::Vacant(entry) => Ok(entry.insert(value)), + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.remove_entry(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); + /// assert_eq!(map.remove(&1), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> + where + K: Borrow, + Q: Hash + Eq, + { + let hash = make_hash::(&self.hash_builder, k); + self.table.remove_entry(hash, equivalent_key(k)) + } +} + +impl HashMap { + /// Creates a raw entry builder for the HashMap. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. After this, insertions into a vacant entry + /// still require an owned key to be provided. + /// + /// Raw entries are useful for such exotic situations as: + /// + /// * Hash memoization + /// * Deferring the creation of an owned key until it is known to be required + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Because raw entries provide much more low-level control, it's much easier + /// to put the HashMap into an inconsistent state which, while memory-safe, + /// will cause the map to produce seemingly random results. Higher-level and + /// more foolproof APIs like `entry` should be preferred when possible. + /// + /// In particular, the hash used to initialized the raw entry must still be + /// consistent with the hash of the key that is ultimately stored in the entry. + /// This is because implementations of HashMap may need to recompute hashes + /// when resizing, at which point only the keys are available. + /// + /// Raw entries give mutable access to the keys. This must not be used + /// to modify how the key would compare or hash, as the map will not re-evaluate + /// where the key should go, meaning the keys may become "lost" if their + /// location does not reflect their state. For instance, if you change a key + /// so that the map now contains keys which compare equal, search may start + /// acting erratically, with two keys randomly masking each other. Implementations + /// are free to assume this doesn't happen (within the limits of memory-safety). + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S, A> { + RawEntryBuilderMut { map: self } + } + + /// Creates a raw immutable entry builder for the HashMap. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. + /// + /// This is useful for + /// * Hash memoization + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Unless you are in such a situation, higher-level and more foolproof APIs like + /// `get` should be preferred. + /// + /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S, A> { + RawEntryBuilder { map: self } + } +} + +impl PartialEq for HashMap +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, + A: Allocator + Clone, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, + A: Allocator + Clone, +{ +} + +impl Debug for HashMap +where + K: Debug, + V: Debug, + A: Allocator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +impl Default for HashMap +where + S: Default, + A: Default + Allocator + Clone, +{ + /// Creates an empty `HashMap`, with the `Default` value for the hasher and allocator. + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self::with_hasher_in(Default::default(), Default::default()) + } +} + +impl Index<&Q> for HashMap +where + K: Eq + Hash + Borrow, + Q: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. + #[cfg_attr(feature = "inline-more", inline)] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +/// An iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashMap.html#method.iter +/// [`HashMap`]: struct.HashMap.html +pub struct Iter<'a, K, V> { + inner: RawIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashMap.html#method.iter_mut +/// [`HashMap`]: struct.HashMap.html +pub struct IterMut<'a, K, V> { + inner: RawIter<(K, V)>, + // To ensure invariance with respect to V + marker: PhantomData<(&'a K, &'a mut V)>, +} + +// We override the default Send impl which has K: Sync instead of K: Send. Both +// are correct, but this one is more general since it allows keys which +// implement Send but not Sync. +unsafe impl Send for IterMut<'_, K, V> {} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.HashMap.html#method.into_iter +/// [`HashMap`]: struct.HashMap.html +pub struct IntoIter { + inner: RawIntoIter<(K, V), A>, +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// An iterator over the keys of a `HashMap`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.HashMap.html#method.keys +/// [`HashMap`]: struct.HashMap.html +pub struct Keys<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Keys { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.HashMap.html#method.values +/// [`HashMap`]: struct.HashMap.html +pub struct Values<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Values { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A draining iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.HashMap.html#method.drain +/// [`HashMap`]: struct.HashMap.html +pub struct Drain<'a, K, V, A: Allocator + Clone = Global> { + inner: RawDrain<'a, (K, V), A>, +} + +impl Drain<'_, K, V, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// A draining iterator over entries of a `HashMap` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain_filter`]: struct.HashMap.html#method.drain_filter +/// [`HashMap`]: struct.HashMap.html +pub struct DrainFilter<'a, K, V, F, A: Allocator + Clone = Global> +where + F: FnMut(&K, &mut V) -> bool, +{ + f: F, + inner: DrainFilterInner<'a, K, V, A>, +} + +impl<'a, K, V, F, A> Drop for DrainFilter<'a, K, V, F, A> +where + F: FnMut(&K, &mut V) -> bool, + A: Allocator + Clone, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + while let Some(item) = self.next() { + let guard = ConsumeAllOnDrop(self); + drop(item); + mem::forget(guard); + } + } +} + +pub(super) struct ConsumeAllOnDrop<'a, T: Iterator>(pub &'a mut T); + +impl Drop for ConsumeAllOnDrop<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + self.0.for_each(drop) + } +} + +impl Iterator for DrainFilter<'_, K, V, F, A> +where + F: FnMut(&K, &mut V) -> bool, + A: Allocator + Clone, +{ + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner.next(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +/// Portions of `DrainFilter` shared with `set::DrainFilter` +pub(super) struct DrainFilterInner<'a, K, V, A: Allocator + Clone> { + pub iter: RawIter<(K, V)>, + pub table: &'a mut RawTable<(K, V), A>, +} + +impl DrainFilterInner<'_, K, V, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn next(&mut self, f: &mut F) -> Option<(K, V)> + where + F: FnMut(&K, &mut V) -> bool, + { + unsafe { + while let Some(item) = self.iter.next() { + let &mut (ref key, ref mut value) = item.as_mut(); + if f(key, value) { + return Some(self.table.remove(item)); + } + } + } + None + } +} + +/// A mutable iterator over the values of a `HashMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.HashMap.html#method.values_mut +/// [`HashMap`]: struct.HashMap.html +pub struct ValuesMut<'a, K, V> { + inner: IterMut<'a, K, V>, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry_mut`] docs for usage examples. +/// +/// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator + Clone = Global> { + map: &'a mut HashMap, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This is a lower-level version of [`Entry`]. +/// +/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], +/// then calling one of the methods of that [`RawEntryBuilderMut`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`Entry`]: enum.Entry.html +/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html +pub enum RawEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { + /// An occupied entry. + Occupied(RawOccupiedEntryMut<'a, K, V, S, A>), + /// A vacant entry. + Vacant(RawVacantEntryMut<'a, K, V, S, A>), +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +pub struct RawOccupiedEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +unsafe impl Send for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Send, + V: Send, + A: Send + Allocator + Clone, +{ +} +unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Sync, + V: Sync, + A: Send + Allocator + Clone, +{ +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry`] docs for usage examples. +/// +/// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry +pub struct RawEntryBuilder<'a, K, V, S, A: Allocator + Clone = Global> { + map: &'a HashMap, +} + +impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given key. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + S: BuildHasher, + K: Borrow, + Q: Hash + Eq, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Creates a `RawEntryMut` from the given key and its hash. + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + K: Borrow, + Q: Eq, + { + self.from_hash(hash, equivalent(k)) + } +} + +impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given hash. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + self.search(hash, is_match) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + match self.map.table.find(hash, |(k, _)| is_match(k)) { + Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { + elem, + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + None => RawEntryMut::Vacant(RawVacantEntryMut { + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + } + } +} + +impl<'a, K, V, S, A: Allocator + Clone> RawEntryBuilder<'a, K, V, S, A> { + /// Access an entry by key. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> + where + S: BuildHasher, + K: Borrow, + Q: Hash + Eq, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Access an entry by a key and its hash. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> + where + K: Borrow, + Q: Eq, + { + self.from_hash(hash, equivalent(k)) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + match self.map.table.get(hash, |(k, _)| is_match(k)) { + Some(&(ref key, ref value)) => Some((key, value)), + None => None, + } + } + + /// Access an entry by hash. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + self.search(hash, is_match) + } +} + +impl<'a, K, V, S, A: Allocator + Clone> RawEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry, and returns a RawOccupiedEntryMut. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.raw_entry_mut().from_key("horseyland").insert("horseyland", 37); + /// + /// assert_eq!(entry.remove_entry(), ("horseyland", 37)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(mut entry) => { + entry.insert(value); + entry + } + RawEntryMut::Vacant(entry) => entry.insert_entry(key, value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| { + /// ("poneyland", "hoho".to_string()) + /// }); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => { + let (k, v) = default(); + entry.insert(k, v) + } + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 0); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut K, &mut V), + { + match self { + RawEntryMut::Occupied(mut entry) => { + { + let (k, v) = entry.get_key_value_mut(); + f(k, v); + } + RawEntryMut::Occupied(entry) + } + RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RawEntryMut; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// RawEntryMut::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// }, + /// RawEntryMut::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + RawEntryMut::Occupied(entry) => entry.replace_entry_with(f), + RawEntryMut::Vacant(_) => self, + } + } +} + +impl<'a, K, V, S, A: Allocator + Clone> RawOccupiedEntryMut<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Gets a mutable reference to the key in the entry. + #[cfg_attr(feature = "inline-more", inline)] + pub fn key_mut(&mut self) -> &mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Converts the entry into a mutable reference to the key in the entry + /// with a lifetime bound to the map itself. + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> &'a mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Gets a reference to the value in the entry. + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a mutable reference to the value in the entry. + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a reference to the key and value in the entry. + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value(&mut self) -> (&K, &V) { + unsafe { + let &(ref key, ref value) = self.elem.as_ref(); + (key, value) + } + } + + /// Gets a mutable reference to the key and value in the entry. + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Converts the OccupiedEntry into a mutable reference to the key and value in the entry + /// with a lifetime bound to the map itself. + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Sets the value of the entry, and returns the entry's old value. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Sets the value of the entry, and returns the entry's old value. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_key(&mut self, key: K) -> K { + mem::replace(self.key_mut(), key) + } + + /// Takes the value out of the entry, and returns it. + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Take the ownership of the key and value from the map. + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem) } + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> RawEntryMut<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let still_occupied = self + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + f(&key, value).map(|new_value| (key, new_value)) + }); + + if still_occupied { + RawEntryMut::Occupied(self) + } else { + RawEntryMut::Vacant(RawVacantEntryMut { + table: self.table, + hash_builder: self.hash_builder, + }) + } + } + } +} + +impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let hash = make_insert_hash::(self.hash_builder, &key); + self.insert_hashed_nocheck(hash, key, value) + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::shadow_unrelated)] + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let &mut (ref mut k, ref mut v) = self.table.insert_entry( + hash, + (key, value), + make_hasher::(self.hash_builder), + ); + (k, v) + } + + /// Set the value of an entry with a custom hasher function. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_with_hasher( + self, + hash: u64, + key: K, + value: V, + hasher: H, + ) -> (&'a mut K, &'a mut V) + where + H: Fn(&K) -> u64, + { + let &mut (ref mut k, ref mut v) = self + .table + .insert_entry(hash, (key, value), |x| hasher(&x.0)); + (k, v) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let hash = make_insert_hash::(self.hash_builder, &key); + let elem = self.table.insert( + hash, + (key, value), + make_hasher::(self.hash_builder), + ); + RawOccupiedEntryMut { + elem, + table: self.table, + hash_builder: self.hash_builder, + } + } +} + +impl Debug for RawEntryBuilderMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +impl Debug for RawEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), + RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), + } + } +} + +impl Debug for RawOccupiedEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawOccupiedEntryMut") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +impl Debug for RawVacantEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish() + } +} + +impl Debug for RawEntryBuilder<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.entry +pub enum Entry<'a, K, V, S, A = Global> +where + A: Allocator + Clone, +{ + /// An occupied entry. + Occupied(OccupiedEntry<'a, K, V, S, A>), + + /// A vacant entry. + Vacant(VacantEntry<'a, K, V, S, A>), +} + +impl Debug for Entry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +pub struct OccupiedEntry<'a, K, V, S, A: Allocator + Clone = Global> { + hash: u64, + key: Option, + elem: Bucket<(K, V)>, + table: &'a mut HashMap, +} + +unsafe impl Send for OccupiedEntry<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator + Clone, +{ +} +unsafe impl Sync for OccupiedEntry<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator + Clone, +{ +} + +impl Debug for OccupiedEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +pub struct VacantEntry<'a, K, V, S, A: Allocator + Clone = Global> { + hash: u64, + key: K, + table: &'a mut HashMap, +} + +impl Debug for VacantEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. +/// +/// Contains the occupied entry, and the value that was not inserted. +pub struct OccupiedError<'a, K, V, S, A: Allocator + Clone = Global> { + /// The entry in the map that was already occupied. + pub entry: OccupiedEntry<'a, K, V, S, A>, + /// The value which was not inserted, because the entry was already occupied. + pub value: V, +} + +impl Debug for OccupiedError<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedError") + .field("key", self.entry.key()) + .field("old_value", self.entry.get()) + .field("new_value", &self.value) + .finish() + } +} + +impl<'a, K: Debug, V: Debug, S, A: Allocator + Clone> fmt::Display + for OccupiedError<'a, K, V, S, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "failed to insert {:?}, key {:?} already exists with value {:?}", + self.value, + self.entry.key(), + self.entry.get(), + ) + } +} + +impl<'a, K, V, S, A: Allocator + Clone> IntoIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +impl<'a, K, V, S, A: Allocator + Clone> IntoIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Not possible with .iter() + /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.table.into_iter(), + } + } +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_ref(); + Some((&r.0, &r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_mut(); + Some((&r.0, &mut r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for IterMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IterMut<'_, K, V> {} + +impl fmt::Debug for IterMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Keys<'_, K, V> {} + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Values<'_, K, V> {} + +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a mut V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for ValuesMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for ValuesMut<'_, K, V> {} + +impl fmt::Debug for ValuesMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter()).finish() + } +} + +impl<'a, K, V, A: Allocator + Clone> Iterator for Drain<'a, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for Drain<'_, K, V, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, K, V, A> {} + +impl fmt::Debug for Drain<'_, K, V, A> +where + K: fmt::Debug, + V: fmt::Debug, + A: Allocator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V, S, A: Allocator + Clone> Entry<'a, K, V, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(mut entry) => { + entry.insert(value); + entry + } + Entry::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, usize> = HashMap::new(); + /// + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// + /// assert_eq!(map["poneyland"], 9); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// Entry::Vacant(e) => assert_eq!(e.key(), &"poneyland"), + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + Entry::Occupied(entry) => entry.replace_entry_with(f), + Entry::Vacant(_) => self, + } + } +} + +impl<'a, K, V: Default, S, A: Allocator + Clone> Entry<'a, K, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, S, A: Allocator + Clone> OccupiedEntry<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.table.remove(self.elem) } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, mut value: V) -> V { + let old_value = self.get_mut(); + mem::swap(&mut value, old_value); + value + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(Rc::new("Stringthing".to_string()), 15); + /// + /// let my_key = Rc::new("Stringthing".to_string()); + /// + /// if let Entry::Occupied(entry) = map.entry(my_key) { + /// // Also replace the key with a handle to our other key. + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// } + /// + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let mut known_strings: Vec> = Vec::new(); + /// + /// // Initialise known strings, run program, etc. + /// + /// reclaim_memory(&mut map, &known_strings); + /// + /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { + /// for s in known_strings { + /// if let Entry::Occupied(entry) = map.entry(s.clone()) { + /// // Replaces the entry's key with our version of it in `known_strings`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap()) + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.insert("poneyland", 42); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(key); + None + } + }); + + if let Some(key) = spare_key { + Entry::Vacant(VacantEntry { + hash: self.hash, + key, + table: self.table, + }) + } else { + Entry::Occupied(self) + } + } + } +} + +impl<'a, K, V, S, A: Allocator + Clone> VacantEntry<'a, K, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key, value), + make_hasher::(&self.table.hash_builder), + ); + &mut entry.1 + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key, value), + make_hasher::(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + key: None, + elem, + table: self.table, + } + } +} + +impl FromIterator<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator + Clone, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: T) -> Self { + let iter = iter.into_iter(); + let mut map = + Self::with_capacity_and_hasher_in(iter.size_hint().0, S::default(), A::default()); + iter.for_each(|(k, v)| { + map.insert(k, v); + }); + map + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl Extend<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + self.reserve(reserve); + iter.for_each(move |(k, v)| { + self.insert(k, v); + }); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if self.is_empty() { + additional + } else { + (additional + 1) / 2 + }; + self.reserve(reserve); + } +} + +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator + Clone, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (&'a K, &'a V)) { + self.insert(*k, *v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { + v + } + fn map_val<'new>(v: HashMap) -> HashMap { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { + v + } + fn into_iter_key<'new, A: Allocator + Clone>( + v: IntoIter<&'static str, u8, A>, + ) -> IntoIter<&'new str, u8, A> { + v + } + fn into_iter_val<'new, A: Allocator + Clone>( + v: IntoIter, + ) -> IntoIter { + v + } + fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { + v + } + fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { + v + } + fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { + v + } + fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { + v + } + fn drain<'new>( + d: Drain<'static, &'static str, &'static str>, + ) -> Drain<'new, &'new str, &'new str> { + d + } +} + +#[cfg(test)] +mod test_map { + use super::DefaultHashBuilder; + use super::Entry::{Occupied, Vacant}; + use super::{HashMap, RawEntryMut}; + use crate::TryReserveError::*; + use rand::{rngs::SmallRng, Rng, SeedableRng}; + use std::borrow::ToOwned; + use std::cell::RefCell; + use std::usize; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); + } + + #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); + } + + #[test] + fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); + } + + #[test] + fn test_clone() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + let m2 = m.clone(); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + #[test] + fn test_clone_from() { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + m2.clone_from(&m); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } + + #[derive(Hash, PartialEq, Eq)] + struct Droppable { + k: usize, + } + + impl Droppable { + fn new(k: usize) -> Droppable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Droppable { k } + } + } + + impl Drop for Droppable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } + } + + impl Clone for Droppable { + fn clone(&self) -> Self { + Droppable::new(self.k) + } + } + + #[test] + fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = vec![0; 200]; + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Droppable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i + 100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_into_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = vec![0; 200]; + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); + + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_empty_remove() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.remove(&0), None); + } + + #[test] + fn test_empty_entry() { + let mut m: HashMap = HashMap::new(); + match m.entry(0) { + Occupied(_) => panic!(), + Vacant(_) => {} + } + assert!(*m.entry(0).or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.drain().next(), None); + assert_eq!(m.keys().next(), None); + assert_eq!(m.values().next(), None); + assert_eq!(m.values_mut().next(), None); + assert_eq!(m.iter().next(), None); + assert_eq!(m.iter_mut().next(), None); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_iter().next(), None); + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: takes too long + fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + + for j in 1..=i { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in i + 1..1001 { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in 1001..2001 { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in 1..1001 { + assert!(m.remove(&i).is_some()); + + for j in 1..=i { + assert!(!m.contains_key(&j)); + } + + for j in i + 1..1001 { + assert!(m.contains_key(&j)); + } + } + + for i in 1..1001 { + assert!(!m.contains_key(&i)); + } + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in (1..1001).rev() { + assert!(m.remove(&i).is_some()); + + for j in i..1001 { + assert!(!m.contains_key(&j)); + } + + for j in 1..i { + assert!(m.contains_key(&j)); + } + } + } + } + + #[test] + fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), + Some(x) => *x = new, + } + assert_eq!(m.get(&5), Some(&new)); + } + + #[test] + fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(!m.insert(1, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 3); + } + + #[test] + fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); + } + + #[test] + fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + } + + #[test] + fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); + } + + #[test] + fn test_remove() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_remove_entry() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove_entry(&1), Some((1, 2))); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value = (*value) * 2 + } + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2), + } + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); + } + + #[test] + fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{:?}", map); + + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{:?}", empty), "{}"); + } + + #[test] + fn test_expand() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + + let mut i = 0; + let old_raw_cap = m.raw_capacity(); + while old_raw_cap == m.raw_capacity() { + m.insert(i, i); + i += 1; + } + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + } + + #[test] + fn test_behavior_resize_policy() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert_eq!(m.raw_capacity(), 1); + assert!(m.is_empty()); + + m.insert(0, 0); + m.remove(&0); + assert!(m.is_empty()); + let initial_raw_cap = m.raw_capacity(); + m.reserve(initial_raw_cap); + let raw_cap = m.raw_capacity(); + + assert_eq!(raw_cap, initial_raw_cap * 2); + + let mut i = 0; + for _ in 0..raw_cap * 3 / 4 { + m.insert(i, i); + i += 1; + } + // three quarters full + + assert_eq!(m.len(), i); + assert_eq!(m.raw_capacity(), raw_cap); + + for _ in 0..raw_cap / 4 { + m.insert(i, i); + i += 1; + } + // half full + + let new_raw_cap = m.raw_capacity(); + assert_eq!(new_raw_cap, raw_cap * 2); + + for _ in 0..raw_cap / 2 - 1 { + i -= 1; + m.remove(&i); + assert_eq!(m.raw_capacity(), new_raw_cap); + } + // A little more than one quarter full. + m.shrink_to_fit(); + assert_eq!(m.raw_capacity(), raw_cap); + // again, a little more than half full + for _ in 0..raw_cap / 2 { + i -= 1; + m.remove(&i); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + assert_eq!(m.raw_capacity(), initial_raw_cap); + } + + #[test] + fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + + assert_eq!(map.iter().len(), xs.len() - 1); + } + + #[test] + fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[&2], 1); + } + + #[test] + #[should_panic] + fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + map[&4]; + } + + #[test] + fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + SmallRng::from_seed(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10, 10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10, 10); + match m.entry(x) { + Vacant(_) => {} + Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } + + #[test] + fn test_capacity_not_less_than_len() { + let mut a = HashMap::new(); + let mut item = 0; + + for _ in 0..116 { + a.insert(item, 0); + item += 1; + } + + assert!(a.capacity() > a.len()); + + let free = a.capacity() - a.len(); + for _ in 0..free { + a.insert(item, 0); + item += 1; + } + + assert_eq!(a.len(), a.capacity()); + + // Insert at capacity should cause allocation. + a.insert(item, 0); + assert!(a.capacity() > a.len()); + } + + #[test] + fn test_occupied_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key.clone(), value.clone()); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry(key.clone()) { + Vacant(_) => panic!(), + Occupied(e) => assert_eq!(key, *e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry(key.clone()) { + Occupied(_) => panic!(), + Vacant(e) => { + assert_eq!(key, *e.key()); + e.insert(value.clone()); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry(key) { + Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + Vacant(_) => panic!(), + }; + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .insert(key, value) + .replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.raw_entry_mut().from_key(&key) { + RawEntryMut::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + RawEntryMut::Vacant(_) => panic!(), + }; + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|_, _| panic!()); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_replace_entry_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + SmallRng::from_seed(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10, 10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10, 10); + m.entry(x).and_replace_entry_with(|_, _| None); + check(&m); + } + } + + #[test] + fn test_retain() { + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); + } + + #[test] + fn test_drain_filter() { + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + let drained = map.drain_filter(|&k, _| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); + assert_eq!(map.len(), 4); + } + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + drop(map.drain_filter(|&k, _| k % 2 == 0)); + assert_eq!(map.len(), 4); + } + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613) + fn test_try_reserve() { + let mut empty_bytes: HashMap = HashMap::new(); + + const MAX_USIZE: usize = usize::MAX; + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { + } else { + // This may succeed if there is enough free memory. Attempt to + // allocate a second hashmap to ensure the allocation will fail. + let mut empty_bytes2: HashMap = HashMap::new(); + if let Err(AllocError { .. }) = empty_bytes2.try_reserve(MAX_USIZE / 8) { + } else { + panic!("usize::MAX / 8 should trigger an OOM!"); + } + } + } + + #[test] + fn test_raw_entry() { + use super::RawEntryMut::{Occupied, Vacant}; + + let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let compute_hash = |map: &HashMap, k: i32| -> u64 { + super::make_insert_hash::(map.hasher(), &k) + }; + + // Existing key (insert) + match map.raw_entry_mut().from_key(&1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + let hash1 = compute_hash(&map, 1); + assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); + assert_eq!( + map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), + (&1, &100) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), + (&1, &100) + ); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.raw_entry_mut().from_key(&2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + let hash2 = compute_hash(&map, 2); + assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); + assert_eq!( + map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), + (&2, &200) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), + (&2, &200) + ); + assert_eq!(map.len(), 6); + + // Existing key (take) + let hash3 = compute_hash(&map, 3); + match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove_entry(), (3, 30)); + } + } + assert_eq!(map.raw_entry().from_key(&3), None); + assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); + assert_eq!(map.len(), 5); + + // Nonexistent key (insert) + match map.raw_entry_mut().from_key(&10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); + } + } + assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); + assert_eq!(map.len(), 6); + + // Ensure all lookup methods produce equivalent results. + for k in 0..12 { + let hash = compute_hash(&map, k); + let v = map.get(&k).cloned(); + let kv = v.as_ref().map(|v| (&k, v)); + + assert_eq!(map.raw_entry().from_key(&k), kv); + assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + + match map.raw_entry_mut().from_key(&k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_hash(hash, |q| *q == k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + } + } + + #[test] + fn test_key_without_hash_impl() { + #[derive(Debug)] + struct IntWrapper(u64); + + let mut m: HashMap = HashMap::default(); + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 0"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(0, IntWrapper(0), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_none()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(1, |k| k.0 == 1) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 1"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(1, IntWrapper(1), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let occupied_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(e) => e, + RawEntryMut::Vacant(..) => panic!("Couldn't find entry for key 0"), + }; + occupied_entry.remove(); + } + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + + #[test] + #[cfg(feature = "raw")] + fn test_into_iter_refresh() { + use core::hash::{BuildHasher, Hash, Hasher}; + + #[cfg(miri)] + const N: usize = 32; + #[cfg(not(miri))] + const N: usize = 128; + + let mut rng = rand::thread_rng(); + for n in 0..N { + let mut m = HashMap::new(); + for i in 0..n { + assert!(m.insert(i, 2 * i).is_none()); + } + let hasher = m.hasher().clone(); + + let mut it = unsafe { m.table.iter() }; + assert_eq!(it.len(), n); + + let mut i = 0; + let mut left = n; + let mut removed = Vec::new(); + loop { + // occasionally remove some elements + if i < n && rng.gen_bool(0.1) { + let mut hsh = hasher.build_hasher(); + i.hash(&mut hsh); + let hash = hsh.finish(); + + unsafe { + let e = m.table.find(hash, |q| q.0.eq(&i)); + if let Some(e) = e { + it.reflect_remove(&e); + let t = m.table.remove(e); + removed.push(t); + left -= 1; + } else { + assert!(removed.contains(&(i, 2 * i)), "{} not in {:?}", i, removed); + let e = m.table.insert( + hash, + (i, 2 * i), + super::make_hasher::(&hasher), + ); + it.reflect_insert(&e); + if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) { + removed.swap_remove(p); + } + left += 1; + } + } + } + + let e = it.next(); + if e.is_none() { + break; + } + assert!(i < n); + let t = unsafe { e.unwrap().as_ref() }; + assert!(!removed.contains(t)); + let (k, v) = t; + assert_eq!(*v, 2 * k); + i += 1; + } + assert!(i <= n); + + // just for safety: + assert_eq!(m.table.len(), left); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_MAP: HashMap = + HashMap::with_hasher(MyHasher); + + let mut map = EMPTY_MAP.clone(); + map.insert(17, "seventeen".to_owned()); + assert_eq!("seventeen", map[&17]); + } + + #[test] + #[cfg(feature = "nightly")] + fn test_get_each_mut() { + use crate::UnavailableMutError::*; + + let mut map = HashMap::new(); + map.insert("foo".to_owned(), 0); + map.insert("bar".to_owned(), 10); + map.insert("baz".to_owned(), 20); + map.insert("qux".to_owned(), 30); + + let xs = map.get_each_mut(["foo", "dud", "foo", "qux"]); + assert_eq!( + xs, + [Ok(&mut 0), Err(Absent), Err(Duplicate(0)), Ok(&mut 30)] + ); + + let ys = map.get_each_key_value_mut(["bar", "baz", "baz", "dip"]); + assert_eq!( + ys, + [ + Ok((&"bar".to_owned(), &mut 10)), + Ok((&"baz".to_owned(), &mut 20)), + Err(Duplicate(1)), + Err(Absent), + ] + ); + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/raw/alloc.rs b/third_party/rust/hashbrown/v0_11/crate/src/raw/alloc.rs new file mode 100644 index 000000000000..de6c455064a5 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/raw/alloc.rs @@ -0,0 +1,72 @@ +pub(crate) use self::inner::{do_alloc, Allocator, Global}; + +#[cfg(feature = "nightly")] +mod inner { + use crate::alloc::alloc::Layout; + pub use crate::alloc::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + alloc + .allocate(layout) + .map(|ptr| ptr.as_non_null_ptr()) + .map_err(|_| ()) + } + + #[cfg(feature = "bumpalo")] + unsafe impl Allocator for crate::BumpWrapper<'_> { + #[inline] + fn allocate(&self, layout: Layout) -> Result, core::alloc::AllocError> { + match self.0.try_alloc_layout(layout) { + Ok(ptr) => Ok(NonNull::slice_from_raw_parts(ptr, layout.size())), + Err(_) => Err(core::alloc::AllocError), + } + } + #[inline] + unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) {} + } +} + +#[cfg(not(feature = "nightly"))] +mod inner { + use crate::alloc::alloc::{alloc, dealloc, Layout}; + use core::ptr::NonNull; + + pub unsafe trait Allocator { + fn allocate(&self, layout: Layout) -> Result, ()>; + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); + } + + #[derive(Copy, Clone)] + pub struct Global; + unsafe impl Allocator for Global { + #[inline] + fn allocate(&self, layout: Layout) -> Result, ()> { + unsafe { NonNull::new(alloc(layout)).ok_or(()) } + } + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + dealloc(ptr.as_ptr(), layout) + } + } + impl Default for Global { + #[inline] + fn default() -> Self { + Global + } + } + + pub fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + alloc.allocate(layout) + } + + #[cfg(feature = "bumpalo")] + unsafe impl Allocator for crate::BumpWrapper<'_> { + #[allow(clippy::map_err_ignore)] + fn allocate(&self, layout: Layout) -> Result, ()> { + self.0.try_alloc_layout(layout).map_err(|_| ()) + } + unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) {} + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/raw/bitmask.rs b/third_party/rust/hashbrown/v0_11/crate/src/raw/bitmask.rs new file mode 100644 index 000000000000..99b2d5341b36 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/raw/bitmask.rs @@ -0,0 +1,122 @@ +use super::imp::{BitMaskWord, BITMASK_MASK, BITMASK_STRIDE}; +#[cfg(feature = "nightly")] +use core::intrinsics; + +/// A bit mask which contains the result of a `Match` operation on a `Group` and +/// allows iterating through them. +/// +/// The bit mask is arranged so that low-order bits represent lower memory +/// addresses for group match results. +/// +/// For implementation reasons, the bits in the set may be sparsely packed, so +/// that there is only one bit-per-byte used (the high bit, 7). If this is the +/// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be +/// performed on counts/indices to normalize this difference. `BITMASK_MASK` is +/// similarly a mask of all the actually-used bits. +#[derive(Copy, Clone)] +pub struct BitMask(pub BitMaskWord); + +#[allow(clippy::use_self)] +impl BitMask { + /// Returns a new `BitMask` with all bits inverted. + #[inline] + #[must_use] + pub fn invert(self) -> Self { + BitMask(self.0 ^ BITMASK_MASK) + } + + /// Flip the bit in the mask for the entry at the given index. + /// + /// Returns the bit's previous state. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + #[cfg(feature = "raw")] + pub unsafe fn flip(&mut self, index: usize) -> bool { + // NOTE: The + BITMASK_STRIDE - 1 is to set the high bit. + let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1); + self.0 ^= mask; + // The bit was set if the bit is now 0. + self.0 & mask == 0 + } + + /// Returns a new `BitMask` with the lowest bit removed. + #[inline] + #[must_use] + pub fn remove_lowest_bit(self) -> Self { + BitMask(self.0 & (self.0 - 1)) + } + /// Returns whether the `BitMask` has at least one set bit. + #[inline] + pub fn any_bit_set(self) -> bool { + self.0 != 0 + } + + /// Returns the first set bit in the `BitMask`, if there is one. + #[inline] + pub fn lowest_set_bit(self) -> Option { + if self.0 == 0 { + None + } else { + Some(unsafe { self.lowest_set_bit_nonzero() }) + } + } + + /// Returns the first set bit in the `BitMask`, if there is one. The + /// bitmask must not be empty. + #[inline] + #[cfg(feature = "nightly")] + pub unsafe fn lowest_set_bit_nonzero(self) -> usize { + intrinsics::cttz_nonzero(self.0) as usize / BITMASK_STRIDE + } + #[inline] + #[cfg(not(feature = "nightly"))] + pub unsafe fn lowest_set_bit_nonzero(self) -> usize { + self.trailing_zeros() + } + + /// Returns the number of trailing zeroes in the `BitMask`. + #[inline] + pub fn trailing_zeros(self) -> usize { + // ARM doesn't have a trailing_zeroes instruction, and instead uses + // reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM + // versions (pre-ARMv7) don't have RBIT and need to emulate it + // instead. Since we only have 1 bit set in each byte on ARM, we can + // use swap_bytes (REV) + leading_zeroes instead. + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE + } else { + self.0.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Returns the number of leading zeroes in the `BitMask`. + #[inline] + pub fn leading_zeros(self) -> usize { + self.0.leading_zeros() as usize / BITMASK_STRIDE + } +} + +impl IntoIterator for BitMask { + type Item = usize; + type IntoIter = BitMaskIter; + + #[inline] + fn into_iter(self) -> BitMaskIter { + BitMaskIter(self) + } +} + +/// Iterator over the contents of a `BitMask`, returning the indicies of set +/// bits. +pub struct BitMaskIter(BitMask); + +impl Iterator for BitMaskIter { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + let bit = self.0.lowest_set_bit()?; + self.0 = self.0.remove_lowest_bit(); + Some(bit) + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/raw/generic.rs b/third_party/rust/hashbrown/v0_11/crate/src/raw/generic.rs new file mode 100644 index 000000000000..ef066e8d0881 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/raw/generic.rs @@ -0,0 +1,151 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::{mem, ptr}; + +// Use the native word size as the group size. Using a 64-bit group size on +// a 32-bit architecture will just end up being more expensive because +// shifts and multiplies will need to be emulated. +#[cfg(any( + target_pointer_width = "64", + target_arch = "aarch64", + target_arch = "x86_64", +))] +type GroupWord = u64; +#[cfg(all( + target_pointer_width = "32", + not(target_arch = "aarch64"), + not(target_arch = "x86_64"), +))] +type GroupWord = u32; + +pub type BitMaskWord = GroupWord; +pub const BITMASK_STRIDE: usize = 8; +// We only care about the highest bit of each byte for the mask. +#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)] +pub const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080_u64 as GroupWord; + +/// Helper function to replicate a byte across a `GroupWord`. +#[inline] +fn repeat(byte: u8) -> GroupWord { + GroupWord::from_ne_bytes([byte; Group::WIDTH]) +} + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a word-sized integer. +#[derive(Copy, Clone)] +pub struct Group(GroupWord); + +// We perform all operations in the native endianess, and convert to +// little-endian just before creating a BitMask. The can potentially +// enable the compiler to eliminate unnecessary byte swaps if we are +// only checking whether a BitMask is empty. +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub unsafe fn load(ptr: *const u8) -> Self { + Group(ptr::read_unaligned(ptr.cast())) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(ptr::read(ptr.cast())) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + ptr::write(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which *may* + /// have the given value. + /// + /// This function may return a false positive in certain cases where + /// the byte in the group differs from the searched value only in its + /// lowest bit. This is fine because: + /// - This never happens for `EMPTY` and `DELETED`, only full entries. + /// - The check for key equality will catch these. + /// - This only happens if there is at least 1 true match. + /// - The chance of this happening is very low (< 1% chance per byte). + #[inline] + pub fn match_byte(self, byte: u8) -> BitMask { + // This algorithm is derived from + // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord + let cmp = self.0 ^ repeat(byte); + BitMask((cmp.wrapping_sub(repeat(0x01)) & !cmp & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub fn match_empty(self) -> BitMask { + // If the high bit is set, then the byte must be either: + // 1111_1111 (EMPTY) or 1000_0000 (DELETED). + // So we can just check if the top two bits are 1 by ANDing them. + BitMask((self.0 & (self.0 << 1) & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub fn match_empty_or_deleted(self) -> BitMask { + // A byte is EMPTY or DELETED iff the high bit is set + BitMask((self.0 & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub fn match_full(self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let full = 1000_0000 (true) or 0000_0000 (false) + // !1000_0000 + 1 = 0111_1111 + 1 = 1000_0000 (no carry) + // !0000_0000 + 0 = 1111_1111 + 0 = 1111_1111 (no carry) + let full = !self.0 & repeat(0x80); + Group(!full + (full >> 7)) + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/raw/mod.rs b/third_party/rust/hashbrown/v0_11/crate/src/raw/mod.rs new file mode 100644 index 000000000000..3ae6980333ab --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/raw/mod.rs @@ -0,0 +1,2262 @@ +use crate::alloc::alloc::{handle_alloc_error, Layout}; +use crate::scopeguard::guard; +use crate::TryReserveError; +#[cfg(feature = "nightly")] +use crate::UnavailableMutError; +use core::hint; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::mem::ManuallyDrop; +#[cfg(feature = "nightly")] +use core::mem::MaybeUninit; +use core::ptr::NonNull; + +cfg_if! { + // Use the SSE2 implementation if possible: it allows us to scan 16 buckets + // at once instead of 8. We don't bother with AVX since it would require + // runtime dispatch and wouldn't gain us much anyways: the probability of + // finding a match drops off drastically after the first few buckets. + // + // I attempted an implementation on ARM using NEON instructions, but it + // turns out that most NEON instructions have multi-cycle latency, which in + // the end outweighs any gains over the generic implementation. + if #[cfg(all( + target_feature = "sse2", + any(target_arch = "x86", target_arch = "x86_64"), + not(miri) + ))] { + mod sse2; + use sse2 as imp; + } else { + #[path = "generic.rs"] + mod generic; + use generic as imp; + } +} + +mod alloc; +pub(crate) use self::alloc::{do_alloc, Allocator, Global}; + +mod bitmask; + +use self::bitmask::{BitMask, BitMaskIter}; +use self::imp::Group; + +// Branch prediction hint. This is currently only available on nightly but it +// consistently improves performance by 10-15%. +#[cfg(feature = "nightly")] +use core::intrinsics::{likely, unlikely}; + +// On stable we can use #[cold] to get a equivalent effect: this attributes +// suggests that the function is unlikely to be called +#[cfg(not(feature = "nightly"))] +#[inline] +#[cold] +fn cold() {} + +#[cfg(not(feature = "nightly"))] +#[inline] +fn likely(b: bool) -> bool { + if !b { + cold() + } + b +} +#[cfg(not(feature = "nightly"))] +#[inline] +fn unlikely(b: bool) -> bool { + if b { + cold() + } + b +} + +#[cfg(feature = "nightly")] +#[cfg_attr(feature = "inline-more", inline)] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + to.offset_from(from) as usize +} +#[cfg(not(feature = "nightly"))] +#[cfg_attr(feature = "inline-more", inline)] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + (to as usize - from as usize) / mem::size_of::() +} + +/// Whether memory allocation errors should return an error or abort. +#[derive(Copy, Clone)] +enum Fallibility { + Fallible, + Infallible, +} + +impl Fallibility { + /// Error to return on capacity overflow. + #[cfg_attr(feature = "inline-more", inline)] + fn capacity_overflow(self) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::CapacityOverflow, + Fallibility::Infallible => panic!("Hash table capacity overflow"), + } + } + + /// Error to return on allocation error. + #[cfg_attr(feature = "inline-more", inline)] + fn alloc_err(self, layout: Layout) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::AllocError { layout }, + Fallibility::Infallible => handle_alloc_error(layout), + } + } +} + +/// Control byte value for an empty bucket. +const EMPTY: u8 = 0b1111_1111; + +/// Control byte value for a deleted bucket. +const DELETED: u8 = 0b1000_0000; + +/// Checks whether a control byte represents a full bucket (top bit is clear). +#[inline] +fn is_full(ctrl: u8) -> bool { + ctrl & 0x80 == 0 +} + +/// Checks whether a control byte represents a special value (top bit is set). +#[inline] +fn is_special(ctrl: u8) -> bool { + ctrl & 0x80 != 0 +} + +/// Checks whether a special control value is EMPTY (just check 1 bit). +#[inline] +fn special_is_empty(ctrl: u8) -> bool { + debug_assert!(is_special(ctrl)); + ctrl & 0x01 != 0 +} + +/// Primary hash function, used to select the initial bucket to probe from. +#[inline] +#[allow(clippy::cast_possible_truncation)] +fn h1(hash: u64) -> usize { + // On 32-bit platforms we simply ignore the higher hash bits. + hash as usize +} + +/// Secondary hash function, saved in the low 7 bits of the control byte. +#[inline] +#[allow(clippy::cast_possible_truncation)] +fn h2(hash: u64) -> u8 { + // Grab the top 7 bits of the hash. While the hash is normally a full 64-bit + // value, some hash functions (such as FxHash) produce a usize result + // instead, which means that the top 32 bits are 0 on 32-bit platforms. + let hash_len = usize::min(mem::size_of::(), mem::size_of::()); + let top7 = hash >> (hash_len * 8 - 7); + (top7 & 0x7f) as u8 // truncation +} + +/// Probe sequence based on triangular numbers, which is guaranteed (since our +/// table size is a power of two) to visit every group of elements exactly once. +/// +/// A triangular probe has us jump by 1 more group every time. So first we +/// jump by 1 group (meaning we just continue our linear scan), then 2 groups +/// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. +/// +/// Proof that the probe will visit every group in the table: +/// +struct ProbeSeq { + pos: usize, + stride: usize, +} + +impl ProbeSeq { + #[inline] + fn move_next(&mut self, bucket_mask: usize) { + // We should have found an empty bucket by now and ended the probe. + debug_assert!( + self.stride <= bucket_mask, + "Went past end of probe sequence" + ); + + self.stride += Group::WIDTH; + self.pos += self.stride; + self.pos &= bucket_mask; + } +} + +/// Returns the number of buckets needed to hold the given number of items, +/// taking the maximum load factor into account. +/// +/// Returns `None` if an overflow occurs. +// Workaround for emscripten bug emscripten-core/emscripten-fastcomp#258 +#[cfg_attr(target_os = "emscripten", inline(never))] +#[cfg_attr(not(target_os = "emscripten"), inline)] +fn capacity_to_buckets(cap: usize) -> Option { + debug_assert_ne!(cap, 0); + + // For small tables we require at least 1 empty bucket so that lookups are + // guaranteed to terminate if an element doesn't exist in the table. + if cap < 8 { + // We don't bother with a table size of 2 buckets since that can only + // hold a single element. Instead we skip directly to a 4 bucket table + // which can hold 3 elements. + return Some(if cap < 4 { 4 } else { 8 }); + } + + // Otherwise require 1/8 buckets to be empty (87.5% load) + // + // Be careful when modifying this, calculate_layout relies on the + // overflow check here. + let adjusted_cap = cap.checked_mul(8)? / 7; + + // Any overflows will have been caught by the checked_mul. Also, any + // rounding errors from the division above will be cleaned up by + // next_power_of_two (which can't overflow because of the previous divison). + Some(adjusted_cap.next_power_of_two()) +} + +/// Returns the maximum effective capacity for the given bucket mask, taking +/// the maximum load factor into account. +#[inline] +fn bucket_mask_to_capacity(bucket_mask: usize) -> usize { + if bucket_mask < 8 { + // For tables with 1/2/4/8 buckets, we always reserve one empty slot. + // Keep in mind that the bucket mask is one less than the bucket count. + bucket_mask + } else { + // For larger tables we reserve 12.5% of the slots as empty. + ((bucket_mask + 1) / 8) * 7 + } +} + +/// Helper which allows the max calculation for ctrl_align to be statically computed for each T +/// while keeping the rest of `calculate_layout_for` independent of `T` +#[derive(Copy, Clone)] +struct TableLayout { + size: usize, + ctrl_align: usize, +} + +impl TableLayout { + #[inline] + fn new() -> Self { + let layout = Layout::new::(); + Self { + size: layout.size(), + ctrl_align: usize::max(layout.align(), Group::WIDTH), + } + } + + #[inline] + fn calculate_layout_for(self, buckets: usize) -> Option<(Layout, usize)> { + debug_assert!(buckets.is_power_of_two()); + + let TableLayout { size, ctrl_align } = self; + // Manual layout calculation since Layout methods are not yet stable. + let ctrl_offset = + size.checked_mul(buckets)?.checked_add(ctrl_align - 1)? & !(ctrl_align - 1); + let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?; + + Some(( + unsafe { Layout::from_size_align_unchecked(len, ctrl_align) }, + ctrl_offset, + )) + } +} + +/// Returns a Layout which describes the allocation required for a hash table, +/// and the offset of the control bytes in the allocation. +/// (the offset is also one past last element of buckets) +/// +/// Returns `None` if an overflow occurs. +#[cfg_attr(feature = "inline-more", inline)] +fn calculate_layout(buckets: usize) -> Option<(Layout, usize)> { + TableLayout::new::().calculate_layout_for(buckets) +} + +/// A reference to a hash table bucket containing a `T`. +/// +/// This is usually just a pointer to the element itself. However if the element +/// is a ZST, then we instead track the index of the element in the table so +/// that `erase` works properly. +pub struct Bucket { + // Actually it is pointer to next element than element itself + // this is needed to maintain pointer arithmetic invariants + // keeping direct pointer to element introduces difficulty. + // Using `NonNull` for variance and niche layout + ptr: NonNull, +} + +// This Send impl is needed for rayon support. This is safe since Bucket is +// never exposed in a public API. +unsafe impl Send for Bucket {} + +impl Clone for Bucket { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { ptr: self.ptr } + } +} + +impl Bucket { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn from_base_index(base: NonNull, index: usize) -> Self { + let ptr = if mem::size_of::() == 0 { + // won't overflow because index must be less than length + (index + 1) as *mut T + } else { + base.as_ptr().sub(index) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn to_base_index(&self, base: NonNull) -> usize { + if mem::size_of::() == 0 { + self.ptr.as_ptr() as usize - 1 + } else { + offset_from(base.as_ptr(), self.ptr.as_ptr()) + } + } + #[cfg_attr(feature = "inline-more", inline)] + pub fn as_ptr(&self) -> *mut T { + if mem::size_of::() == 0 { + // Just return an arbitrary ZST pointer which is properly aligned + mem::align_of::() as *mut T + } else { + unsafe { self.ptr.as_ptr().sub(1) } + } + } + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn next_n(&self, offset: usize) -> Self { + let ptr = if mem::size_of::() == 0 { + (self.ptr.as_ptr() as usize + offset) as *mut T + } else { + self.ptr.as_ptr().sub(offset) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn drop(&self) { + self.as_ptr().drop_in_place(); + } + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn read(&self) -> T { + self.as_ptr().read() + } + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn write(&self, val: T) { + self.as_ptr().write(val); + } + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn as_ref<'a>(&self) -> &'a T { + &*self.as_ptr() + } + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn as_mut<'a>(&self) -> &'a mut T { + &mut *self.as_ptr() + } + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn copy_from_nonoverlapping(&self, other: &Self) { + self.as_ptr().copy_from_nonoverlapping(other.as_ptr(), 1); + } +} + +/// A raw hash table with an unsafe API. +pub struct RawTable { + table: RawTableInner, + // Tell dropck that we own instances of T. + marker: PhantomData, +} + +/// Non-generic part of `RawTable` which allows functions to be instantiated only once regardless +/// of how many different key-value types are used. +struct RawTableInner { + // Mask to get an index from a hash value. The value is one less than the + // number of buckets in the table. + bucket_mask: usize, + + // [Padding], T1, T2, ..., Tlast, C1, C2, ... + // ^ points here + ctrl: NonNull, + + // Number of elements that can be inserted before we need to grow the table + growth_left: usize, + + // Number of elements in the table, only really used by len() + items: usize, + + alloc: A, +} + +impl RawTable { + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[cfg_attr(feature = "inline-more", inline)] + pub const fn new() -> Self { + Self { + table: RawTableInner::new_in(Global), + marker: PhantomData, + } + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + + /// Allocates a new hash table with at least enough capacity for inserting + /// the given number of elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } +} + +impl RawTable { + /// Creates a new empty hash table without allocating any memory, using the + /// given allocator. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self { + table: RawTableInner::new_in(alloc), + marker: PhantomData, + } + } + + /// Allocates a new hash table with the given number of buckets. + /// + /// The control bytes are left uninitialized. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: A, + buckets: usize, + fallibility: Fallibility, + ) -> Result { + debug_assert!(buckets.is_power_of_two()); + + Ok(Self { + table: RawTableInner::new_uninitialized( + alloc, + TableLayout::new::(), + buckets, + fallibility, + )?, + marker: PhantomData, + }) + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating. + fn fallible_with_capacity( + alloc: A, + capacity: usize, + fallibility: Fallibility, + ) -> Result { + Ok(Self { + table: RawTableInner::fallible_with_capacity( + alloc, + TableLayout::new::(), + capacity, + fallibility, + )?, + marker: PhantomData, + }) + } + + /// Attempts to allocate a new hash table using the given allocator, with at least enough + /// capacity for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Self::fallible_with_capacity(alloc, capacity, Fallibility::Fallible) + } + + /// Allocates a new hash table using the given allocator, with at least enough capacity for + /// inserting the given number of elements without reallocating. + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + match Self::fallible_with_capacity(alloc, capacity, Fallibility::Infallible) { + Ok(capacity) => capacity, + Err(_) => unsafe { hint::unreachable_unchecked() }, + } + } + + /// Deallocates the table without dropping any entries. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn free_buckets(&mut self) { + self.table.free_buckets(TableLayout::new::()) + } + + /// Returns pointer to one past last element of data table. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn data_end(&self) -> NonNull { + NonNull::new_unchecked(self.table.ctrl.as_ptr().cast()) + } + + /// Returns pointer to start of data table. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "nightly")] + pub unsafe fn data_start(&self) -> *mut T { + self.data_end().as_ptr().wrapping_sub(self.buckets()) + } + + /// Returns the index of a bucket from a `Bucket`. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn bucket_index(&self, bucket: &Bucket) -> usize { + bucket.to_base_index(self.data_end()) + } + + /// Returns a pointer to an element in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn bucket(&self, index: usize) -> Bucket { + debug_assert_ne!(self.table.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + /// Erases an element from the table without dropping it. + #[cfg_attr(feature = "inline-more", inline)] + #[deprecated(since = "0.8.1", note = "use erase or remove instead")] + pub unsafe fn erase_no_drop(&mut self, item: &Bucket) { + let index = self.bucket_index(item); + self.table.erase(index) + } + + /// Erases an element from the table, dropping it in place. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + #[allow(deprecated)] + pub unsafe fn erase(&mut self, item: Bucket) { + // Erase the element from the table first since drop might panic. + self.erase_no_drop(&item); + item.drop(); + } + + /// Finds and erases an element from the table, dropping it in place. + /// Returns true if an element was found. + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn erase_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> bool { + // Avoid `Option::map` because it bloats LLVM IR. + if let Some(bucket) = self.find(hash, eq) { + unsafe { self.erase(bucket) }; + true + } else { + false + } + } + + /// Removes an element from the table, returning it. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + #[allow(deprecated)] + pub unsafe fn remove(&mut self, item: Bucket) -> T { + self.erase_no_drop(&item); + item.read() + } + + /// Finds and removes an element from the table, returning it. + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { self.remove(bucket) }), + None => None, + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear_no_drop(&mut self) { + self.table.clear_no_drop() + } + + /// Removes all elements from the table without freeing the backing memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + // Ensure that the table is reset even if one of the drops panic + let mut self_ = guard(self, |self_| self_.clear_no_drop()); + unsafe { + self_.drop_elements(); + } + } + + unsafe fn drop_elements(&mut self) { + if mem::needs_drop::() && self.len() != 0 { + for item in self.iter() { + item.drop(); + } + } + } + + /// Shrinks the table to fit `max(self.len(), min_size)` elements. + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_size: usize, hasher: impl Fn(&T) -> u64) { + // Calculate the minimal number of elements that we need to reserve + // space for. + let min_size = usize::max(self.table.items, min_size); + if min_size == 0 { + *self = Self::new_in(self.table.alloc.clone()); + return; + } + + // Calculate the number of buckets that we need for this number of + // elements. If the calculation overflows then the requested bucket + // count must be larger than what we have right and nothing needs to be + // done. + let min_buckets = match capacity_to_buckets(min_size) { + Some(buckets) => buckets, + None => return, + }; + + // If we have more buckets than we need, shrink the table. + if min_buckets < self.buckets() { + // Fast path if the table is empty + if self.table.items == 0 { + *self = Self::with_capacity_in(min_size, self.table.alloc.clone()) + } else { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + if self + .resize(min_size, hasher, Fallibility::Infallible) + .is_err() + { + unsafe { hint::unreachable_unchecked() } + } + } + } + } + + /// Ensures that at least `additional` items can be inserted into the table + /// without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + if additional > self.table.growth_left { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + if self + .reserve_rehash(additional, hasher, Fallibility::Infallible) + .is_err() + { + unsafe { hint::unreachable_unchecked() } + } + } + } + + /// Tries to ensure that at least `additional` items can be inserted into + /// the table without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + if additional > self.table.growth_left { + self.reserve_rehash(additional, hasher, Fallibility::Fallible) + } else { + Ok(()) + } + } + + /// Out-of-line slow path for `reserve` and `try_reserve`. + #[cold] + #[inline(never)] + fn reserve_rehash( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let new_items = match self.table.items.checked_add(additional) { + Some(new_items) => new_items, + None => return Err(fallibility.capacity_overflow()), + }; + let full_capacity = bucket_mask_to_capacity(self.table.bucket_mask); + if new_items <= full_capacity / 2 { + // Rehash in-place without re-allocating if we have plenty of spare + // capacity that is locked up due to DELETED entries. + self.rehash_in_place(hasher); + Ok(()) + } else { + // Otherwise, conservatively resize to at least the next size up + // to avoid churning deletes into frequent rehashes. + self.resize( + usize::max(new_items, full_capacity + 1), + hasher, + fallibility, + ) + } + } + + /// Rehashes the contents of the table in place (i.e. without changing the + /// allocation). + /// + /// If `hasher` panics then some the table's contents may be lost. + fn rehash_in_place(&mut self, hasher: impl Fn(&T) -> u64) { + unsafe { + // If the hash function panics then properly clean up any elements + // that we haven't rehashed yet. We unfortunately can't preserve the + // element since we lost their hash and have no way of recovering it + // without risking another panic. + self.table.prepare_rehash_in_place(); + + let mut guard = guard(&mut self.table, move |self_| { + if mem::needs_drop::() { + for i in 0..self_.buckets() { + if *self_.ctrl(i) == DELETED { + self_.set_ctrl(i, EMPTY); + self_.bucket::(i).drop(); + self_.items -= 1; + } + } + } + self_.growth_left = bucket_mask_to_capacity(self_.bucket_mask) - self_.items; + }); + + // At this point, DELETED elements are elements that we haven't + // rehashed yet. Find them and re-insert them at their ideal + // position. + 'outer: for i in 0..guard.buckets() { + if *guard.ctrl(i) != DELETED { + continue; + } + + 'inner: loop { + // Hash the current item + let item = guard.bucket(i); + let hash = hasher(item.as_ref()); + + // Search for a suitable place to put it + let new_i = guard.find_insert_slot(hash); + + // Probing works by scanning through all of the control + // bytes in groups, which may not be aligned to the group + // size. If both the new and old position fall within the + // same unaligned group, then there is no benefit in moving + // it and we can just continue to the next item. + if likely(guard.is_in_same_group(i, new_i, hash)) { + guard.set_ctrl_h2(i, hash); + continue 'outer; + } + + // We are moving the current item to a new position. Write + // our H2 to the control byte of the new position. + let prev_ctrl = guard.replace_ctrl_h2(new_i, hash); + if prev_ctrl == EMPTY { + guard.set_ctrl(i, EMPTY); + // If the target slot is empty, simply move the current + // element into the new slot and clear the old control + // byte. + guard.bucket(new_i).copy_from_nonoverlapping(&item); + continue 'outer; + } else { + // If the target slot is occupied, swap the two elements + // and then continue processing the element that we just + // swapped into the old slot. + debug_assert_eq!(prev_ctrl, DELETED); + mem::swap(guard.bucket(new_i).as_mut(), item.as_mut()); + continue 'inner; + } + } + } + + guard.growth_left = bucket_mask_to_capacity(guard.bucket_mask) - guard.items; + mem::forget(guard); + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + fn resize( + &mut self, + capacity: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + unsafe { + let mut new_table = + self.table + .prepare_resize(TableLayout::new::(), capacity, fallibility)?; + + // Copy all elements to the new table. + for item in self.iter() { + // This may panic. + let hash = hasher(item.as_ref()); + + // We can use a simpler version of insert() here since: + // - there are no DELETED entries. + // - we know there is enough space in the table. + // - all elements are unique. + let (index, _) = new_table.prepare_insert_slot(hash); + new_table.bucket(index).copy_from_nonoverlapping(&item); + } + + // We successfully copied all elements without panicking. Now replace + // self with the new table. The old table will have its memory freed but + // the items will not be dropped (since they have been moved into the + // new table). + mem::swap(&mut self.table, &mut new_table); + + Ok(()) + } + } + + /// Inserts a new element into the table, and returns its raw bucket. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket { + unsafe { + let mut index = self.table.find_insert_slot(hash); + + // We can avoid growing the table once we have reached our load + // factor if we are replacing a tombstone. This works since the + // number of EMPTY slots does not change in this case. + let old_ctrl = *self.table.ctrl(index); + if unlikely(self.table.growth_left == 0 && special_is_empty(old_ctrl)) { + self.reserve(1, hasher); + index = self.table.find_insert_slot(hash); + } + + self.table.record_item_insert_at(index, old_ctrl, hash); + + let bucket = self.bucket(index); + bucket.write(value); + bucket + } + } + + /// Attempts to insert a new element without growing the table and return its raw bucket. + /// + /// Returns an `Err` containing the given element if inserting it would require growing the + /// table. + /// + /// This does not check if the given element already exists in the table. + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert_no_grow(&mut self, hash: u64, value: T) -> Result, T> { + unsafe { + match self.table.prepare_insert_no_grow(hash) { + Ok(index) => { + let bucket = self.bucket(index); + bucket.write(value); + Ok(bucket) + } + Err(()) => Err(value), + } + } + } + + /// Inserts a new element into the table, and returns a mutable reference to it. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> &mut T { + unsafe { self.insert(hash, value, hasher).as_mut() } + } + + /// Inserts a new element into the table, without growing the table. + /// + /// There must be enough space in the table to insert the new element. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(any(feature = "raw", feature = "rustc-internal-api"))] + pub fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket { + unsafe { + let (index, old_ctrl) = self.table.prepare_insert_slot(hash); + let bucket = self.table.bucket(index); + + // If we are replacing a DELETED entry then we don't need to update + // the load counter. + self.table.growth_left -= special_is_empty(old_ctrl) as usize; + + bucket.write(value); + self.table.items += 1; + bucket + } + } + + /// Temporary removes a bucket, applying the given function to the removed + /// element and optionally put back the returned value in the same bucket. + /// + /// Returns `true` if the bucket still contains an element + /// + /// This does not check if the given bucket is actually occupied. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn replace_bucket_with(&mut self, bucket: Bucket, f: F) -> bool + where + F: FnOnce(T) -> Option, + { + let index = self.bucket_index(&bucket); + let old_ctrl = *self.table.ctrl(index); + debug_assert!(is_full(old_ctrl)); + let old_growth_left = self.table.growth_left; + let item = self.remove(bucket); + if let Some(new_item) = f(item) { + self.table.growth_left = old_growth_left; + self.table.set_ctrl(index, old_ctrl); + self.table.items += 1; + self.bucket(index).write(new_item); + true + } else { + false + } + } + + /// Searches for an element in the table. + #[inline] + pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { + unsafe { + for bucket in self.iter_hash(hash) { + let elm = bucket.as_ref(); + if likely(eq(elm)) { + return Some(bucket); + } + } + None + } + } + + /// Gets a reference to an element in the table. + #[inline] + pub fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + /// Gets a mutable reference to an element in the table. + #[inline] + pub fn get_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + /// Attempts to get mutable references to `N` entries in the table at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, + /// at most one mutable reference will be returned to any entry. An + /// `Err(UnavailableMutError::Duplicate(i))` in the returned array indicates that a suitable + /// entry exists, but a mutable reference to it already occurs at index `i` in the returned + /// array. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// This method is available only if the `nightly` feature is enabled. + #[cfg(feature = "nightly")] + pub fn get_each_mut( + &mut self, + hashes: [u64; N], + mut eq: impl FnMut(usize, &T) -> bool, + ) -> [Result<&'_ mut T, UnavailableMutError>; N] { + // Collect the requested buckets. + // TODO use `MaybeUninit::uninit_array` here instead once that's stable. + let mut buckets: [MaybeUninit>>; N] = + unsafe { MaybeUninit::uninit().assume_init() }; + for i in 0..N { + buckets[i] = MaybeUninit::new(self.find(hashes[i], |k| eq(i, k))); + } + let buckets: [Option>; N] = unsafe { MaybeUninit::array_assume_init(buckets) }; + + // Walk through the buckets, checking for duplicates and building up the output array. + // TODO use `MaybeUninit::uninit_array` here instead once that's stable. + let mut out: [MaybeUninit>; N] = + unsafe { MaybeUninit::uninit().assume_init() }; + for i in 0..N { + out[i] = MaybeUninit::new( + #[allow(clippy::never_loop)] + 'outer: loop { + for j in 0..i { + match (&buckets[j], &buckets[i]) { + // These two buckets are the same, and we can't safely return a second + // mutable reference to the same entry. + (Some(prev), Some(cur)) if prev.as_ptr() == cur.as_ptr() => { + break 'outer Err(UnavailableMutError::Duplicate(j)); + } + _ => {} + } + } + // This bucket is distinct from all previous buckets (or it doesn't exist), so + // we're clear to return the result of the lookup. + break match &buckets[i] { + None => Err(UnavailableMutError::Absent), + Some(bkt) => unsafe { Ok(bkt.as_mut()) }, + }; + }, + ) + } + + unsafe { MaybeUninit::array_assume_init(out) } + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the table might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.table.items + self.table.growth_left + } + + /// Returns the number of elements in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.table.items + } + + /// Returns the number of buckets in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn buckets(&self) -> usize { + self.table.bucket_mask + 1 + } + + /// Returns an iterator over every element in the table. It is up to + /// the caller to ensure that the `RawTable` outlives the `RawIter`. + /// Because we cannot make the `next` method unsafe on the `RawIter` + /// struct, we have to make the `iter` method unsafe. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn iter(&self) -> RawIter { + let data = Bucket::from_base_index(self.data_end(), 0); + RawIter { + iter: RawIterRange::new(self.table.ctrl.as_ptr(), data, self.table.buckets()), + items: self.table.items, + } + } + + /// Returns an iterator over occupied buckets that could match a given hash. + /// + /// In rare cases, the iterator may return a bucket with a different hash. + /// + /// It is up to the caller to ensure that the `RawTable` outlives the + /// `RawIterHash`. Because we cannot make the `next` method unsafe on the + /// `RawIterHash` struct, we have to make the `iter_hash` method unsafe. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash<'_, T, A> { + RawIterHash::new(self, hash) + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> RawDrain<'_, T, A> { + unsafe { + let iter = self.iter(); + self.drain_iter_from(iter) + } + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn drain_iter_from(&mut self, iter: RawIter) -> RawDrain<'_, T, A> { + debug_assert_eq!(iter.len(), self.len()); + RawDrain { + iter, + table: ManuallyDrop::new(mem::replace(self, Self::new_in(self.table.alloc.clone()))), + orig_table: NonNull::from(self), + marker: PhantomData, + } + } + + /// Returns an iterator which consumes all elements from the table. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + pub unsafe fn into_iter_from(self, iter: RawIter) -> RawIntoIter { + debug_assert_eq!(iter.len(), self.len()); + + let alloc = self.table.alloc.clone(); + let allocation = self.into_allocation(); + RawIntoIter { + iter, + allocation, + marker: PhantomData, + alloc, + } + } + + /// Converts the table into a raw allocation. The contents of the table + /// should be dropped using a `RawIter` before freeing the allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn into_allocation(self) -> Option<(NonNull, Layout)> { + let alloc = if self.table.is_empty_singleton() { + None + } else { + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match calculate_layout::(self.table.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; + Some(( + unsafe { NonNull::new_unchecked(self.table.ctrl.as_ptr().sub(ctrl_offset)) }, + layout, + )) + }; + mem::forget(self); + alloc + } +} + +unsafe impl Send for RawTable where T: Send {} +unsafe impl Sync for RawTable where T: Sync {} + +impl RawTableInner { + #[cfg_attr(feature = "inline-more", inline)] + const fn new_in(alloc: A) -> Self { + Self { + // Be careful to cast the entire slice to a raw pointer. + ctrl: unsafe { NonNull::new_unchecked(Group::static_empty() as *const _ as *mut u8) }, + bucket_mask: 0, + items: 0, + growth_left: 0, + alloc, + } + } +} + +impl RawTableInner { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: A, + table_layout: TableLayout, + buckets: usize, + fallibility: Fallibility, + ) -> Result { + debug_assert!(buckets.is_power_of_two()); + + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(buckets) { + Some(lco) => lco, + None => return Err(fallibility.capacity_overflow()), + }; + + let ptr: NonNull = match do_alloc(&alloc, layout) { + Ok(block) => block.cast(), + Err(_) => return Err(fallibility.alloc_err(layout)), + }; + + let ctrl = NonNull::new_unchecked(ptr.as_ptr().add(ctrl_offset)); + Ok(Self { + ctrl, + bucket_mask: buckets - 1, + items: 0, + growth_left: bucket_mask_to_capacity(buckets - 1), + alloc, + }) + } + + #[inline] + fn fallible_with_capacity( + alloc: A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result { + if capacity == 0 { + Ok(Self::new_in(alloc)) + } else { + unsafe { + let buckets = + capacity_to_buckets(capacity).ok_or_else(|| fallibility.capacity_overflow())?; + + let result = Self::new_uninitialized(alloc, table_layout, buckets, fallibility)?; + result.ctrl(0).write_bytes(EMPTY, result.num_ctrl_bytes()); + + Ok(result) + } + } + } + + /// Searches for an empty or deleted bucket which is suitable for inserting + /// a new element and sets the hash for that slot. + /// + /// There must be at least 1 empty bucket in the table. + #[inline] + unsafe fn prepare_insert_slot(&self, hash: u64) -> (usize, u8) { + let index = self.find_insert_slot(hash); + let old_ctrl = *self.ctrl(index); + self.set_ctrl_h2(index, hash); + (index, old_ctrl) + } + + /// Searches for an empty or deleted bucket which is suitable for inserting + /// a new element. + /// + /// There must be at least 1 empty bucket in the table. + #[inline] + fn find_insert_slot(&self, hash: u64) -> usize { + let mut probe_seq = self.probe_seq(hash); + loop { + unsafe { + let group = Group::load(self.ctrl(probe_seq.pos)); + if let Some(bit) = group.match_empty_or_deleted().lowest_set_bit() { + let result = (probe_seq.pos + bit) & self.bucket_mask; + + // In tables smaller than the group width, trailing control + // bytes outside the range of the table are filled with + // EMPTY entries. These will unfortunately trigger a + // match, but once masked may point to a full bucket that + // is already occupied. We detect this situation here and + // perform a second scan starting at the begining of the + // table. This second scan is guaranteed to find an empty + // slot (due to the load factor) before hitting the trailing + // control bytes (containing EMPTY). + if unlikely(is_full(*self.ctrl(result))) { + debug_assert!(self.bucket_mask < Group::WIDTH); + debug_assert_ne!(probe_seq.pos, 0); + return Group::load_aligned(self.ctrl(0)) + .match_empty_or_deleted() + .lowest_set_bit_nonzero(); + } + + return result; + } + } + probe_seq.move_next(self.bucket_mask); + } + } + + #[allow(clippy::mut_mut)] + #[inline] + unsafe fn prepare_rehash_in_place(&mut self) { + // Bulk convert all full control bytes to DELETED, and all DELETED + // control bytes to EMPTY. This effectively frees up all buckets + // containing a DELETED entry. + for i in (0..self.buckets()).step_by(Group::WIDTH) { + let group = Group::load_aligned(self.ctrl(i)); + let group = group.convert_special_to_empty_and_full_to_deleted(); + group.store_aligned(self.ctrl(i)); + } + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + if self.buckets() < Group::WIDTH { + self.ctrl(0) + .copy_to(self.ctrl(Group::WIDTH), self.buckets()); + } else { + self.ctrl(0) + .copy_to(self.ctrl(self.buckets()), Group::WIDTH); + } + } + + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn bucket(&self, index: usize) -> Bucket { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn data_end(&self) -> NonNull { + NonNull::new_unchecked(self.ctrl.as_ptr().cast()) + } + + /// Returns an iterator-like object for a probe sequence on the table. + /// + /// This iterator never terminates, but is guaranteed to visit each bucket + /// group exactly once. The loop using `probe_seq` must terminate upon + /// reaching a group containing an empty bucket. + #[inline] + fn probe_seq(&self, hash: u64) -> ProbeSeq { + ProbeSeq { + pos: h1(hash) & self.bucket_mask, + stride: 0, + } + } + + /// Returns the index of a bucket for which a value must be inserted if there is enough rooom + /// in the table, otherwise returns error + #[cfg(feature = "raw")] + #[inline] + unsafe fn prepare_insert_no_grow(&mut self, hash: u64) -> Result { + let index = self.find_insert_slot(hash); + let old_ctrl = *self.ctrl(index); + if unlikely(self.growth_left == 0 && special_is_empty(old_ctrl)) { + Err(()) + } else { + self.record_item_insert_at(index, old_ctrl, hash); + Ok(index) + } + } + + #[inline] + unsafe fn record_item_insert_at(&mut self, index: usize, old_ctrl: u8, hash: u64) { + self.growth_left -= special_is_empty(old_ctrl) as usize; + self.set_ctrl_h2(index, hash); + self.items += 1; + } + + #[inline] + fn is_in_same_group(&self, i: usize, new_i: usize, hash: u64) -> bool { + let probe_seq_pos = self.probe_seq(hash).pos; + let probe_index = + |pos: usize| (pos.wrapping_sub(probe_seq_pos) & self.bucket_mask) / Group::WIDTH; + probe_index(i) == probe_index(new_i) + } + + /// Sets a control byte to the hash, and possibly also the replicated control byte at + /// the end of the array. + #[inline] + unsafe fn set_ctrl_h2(&self, index: usize, hash: u64) { + self.set_ctrl(index, h2(hash)) + } + + #[inline] + unsafe fn replace_ctrl_h2(&self, index: usize, hash: u64) -> u8 { + let prev_ctrl = *self.ctrl(index); + self.set_ctrl_h2(index, hash); + prev_ctrl + } + + /// Sets a control byte, and possibly also the replicated control byte at + /// the end of the array. + #[inline] + unsafe fn set_ctrl(&self, index: usize, ctrl: u8) { + // Replicate the first Group::WIDTH control bytes at the end of + // the array without using a branch: + // - If index >= Group::WIDTH then index == index2. + // - Otherwise index2 == self.bucket_mask + 1 + index. + // + // The very last replicated control byte is never actually read because + // we mask the initial index for unaligned loads, but we write it + // anyways because it makes the set_ctrl implementation simpler. + // + // If there are fewer buckets than Group::WIDTH then this code will + // replicate the buckets at the end of the trailing group. For example + // with 2 buckets and a group size of 4, the control bytes will look + // like this: + // + // Real | Replicated + // --------------------------------------------- + // | [A] | [B] | [EMPTY] | [EMPTY] | [A] | [B] | + // --------------------------------------------- + let index2 = ((index.wrapping_sub(Group::WIDTH)) & self.bucket_mask) + Group::WIDTH; + + *self.ctrl(index) = ctrl; + *self.ctrl(index2) = ctrl; + } + + /// Returns a pointer to a control byte. + #[inline] + unsafe fn ctrl(&self, index: usize) -> *mut u8 { + debug_assert!(index < self.num_ctrl_bytes()); + self.ctrl.as_ptr().add(index) + } + + #[inline] + fn buckets(&self) -> usize { + self.bucket_mask + 1 + } + + #[inline] + fn num_ctrl_bytes(&self) -> usize { + self.bucket_mask + 1 + Group::WIDTH + } + + #[inline] + fn is_empty_singleton(&self) -> bool { + self.bucket_mask == 0 + } + + #[allow(clippy::mut_mut)] + #[inline] + unsafe fn prepare_resize( + &self, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result, TryReserveError> { + debug_assert!(self.items <= capacity); + + // Allocate and initialize the new table. + let mut new_table = RawTableInner::fallible_with_capacity( + self.alloc.clone(), + table_layout, + capacity, + fallibility, + )?; + new_table.growth_left -= self.items; + new_table.items = self.items; + + // The hash function may panic, in which case we simply free the new + // table without dropping any elements that may have been copied into + // it. + // + // This guard is also used to free the old table on success, see + // the comment at the bottom of this function. + Ok(guard(new_table, move |self_| { + if !self_.is_empty_singleton() { + self_.free_buckets(table_layout); + } + })) + } + + #[inline] + unsafe fn free_buckets(&mut self, table_layout: TableLayout) { + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(self.buckets()) { + Some(lco) => lco, + None => hint::unreachable_unchecked(), + }; + self.alloc.deallocate( + NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)), + layout, + ); + } + + /// Marks all table buckets as empty without dropping their contents. + #[inline] + fn clear_no_drop(&mut self) { + if !self.is_empty_singleton() { + unsafe { + self.ctrl(0).write_bytes(EMPTY, self.num_ctrl_bytes()); + } + } + self.items = 0; + self.growth_left = bucket_mask_to_capacity(self.bucket_mask); + } + + #[inline] + unsafe fn erase(&mut self, index: usize) { + debug_assert!(is_full(*self.ctrl(index))); + let index_before = index.wrapping_sub(Group::WIDTH) & self.bucket_mask; + let empty_before = Group::load(self.ctrl(index_before)).match_empty(); + let empty_after = Group::load(self.ctrl(index)).match_empty(); + + // If we are inside a continuous block of Group::WIDTH full or deleted + // cells then a probe window may have seen a full block when trying to + // insert. We therefore need to keep that block non-empty so that + // lookups will continue searching to the next probe window. + // + // Note that in this context `leading_zeros` refers to the bytes at the + // end of a group, while `trailing_zeros` refers to the bytes at the + // begining of a group. + let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH { + DELETED + } else { + self.growth_left += 1; + EMPTY + }; + self.set_ctrl(index, ctrl); + self.items -= 1; + } +} + +impl Clone for RawTable { + fn clone(&self) -> Self { + if self.table.is_empty_singleton() { + Self::new_in(self.table.alloc.clone()) + } else { + unsafe { + let mut new_table = ManuallyDrop::new( + // Avoid `Result::ok_or_else` because it bloats LLVM IR. + match Self::new_uninitialized( + self.table.alloc.clone(), + self.table.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }, + ); + + new_table.clone_from_spec(self, |new_table| { + // We need to free the memory allocated for the new table. + new_table.free_buckets(); + }); + + // Return the newly created table. + ManuallyDrop::into_inner(new_table) + } + } + } + + fn clone_from(&mut self, source: &Self) { + if source.table.is_empty_singleton() { + *self = Self::new_in(self.table.alloc.clone()); + } else { + unsafe { + // First, drop all our elements without clearing the control bytes. + self.drop_elements(); + + // If necessary, resize our table to match the source. + if self.buckets() != source.buckets() { + // Skip our drop by using ptr::write. + if !self.table.is_empty_singleton() { + self.free_buckets(); + } + (self as *mut Self).write( + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + match Self::new_uninitialized( + self.table.alloc.clone(), + source.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }, + ); + } + + self.clone_from_spec(source, |self_| { + // We need to leave the table in an empty state. + self_.clear_no_drop() + }); + } + } + } +} + +/// Specialization of `clone_from` for `Copy` types +trait RawTableClone { + unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self)); +} +impl RawTableClone for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + default_fn! { + unsafe fn clone_from_spec(&mut self, source: &Self, on_panic: impl FnMut(&mut Self)) { + self.clone_from_impl(source, on_panic); + } + } +} +#[cfg(feature = "nightly")] +impl RawTableClone for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self, _on_panic: impl FnMut(&mut Self)) { + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + source + .data_start() + .copy_to_nonoverlapping(self.data_start(), self.table.buckets()); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } +} + +impl RawTable { + /// Common code for clone and clone_from. Assumes `self.buckets() == source.buckets()`. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_impl(&mut self, source: &Self, mut on_panic: impl FnMut(&mut Self)) { + // Copy the control bytes unchanged. We do this in a single pass + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + + // The cloning of elements may panic, in which case we need + // to make sure we drop only the elements that have been + // cloned so far. + let mut guard = guard((0, &mut *self), |(index, self_)| { + if mem::needs_drop::() && self_.len() != 0 { + for i in 0..=*index { + if is_full(*self_.table.ctrl(i)) { + self_.bucket(i).drop(); + } + } + } + + // Depending on whether we were called from clone or clone_from, we + // either need to free the memory for the destination table or just + // clear the control bytes. + on_panic(self_); + }); + + for from in source.iter() { + let index = source.bucket_index(&from); + let to = guard.1.bucket(index); + to.write(from.as_ref().clone()); + + // Update the index in case we need to unwind. + guard.0 = index; + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } + + /// Variant of `clone_from` to use when a hasher is available. + #[cfg(feature = "raw")] + pub fn clone_from_with_hasher(&mut self, source: &Self, hasher: impl Fn(&T) -> u64) { + // If we have enough capacity in the table, just clear it and insert + // elements one by one. We don't do this if we have the same number of + // buckets as the source since we can just copy the contents directly + // in that case. + if self.table.buckets() != source.table.buckets() + && bucket_mask_to_capacity(self.table.bucket_mask) >= source.len() + { + self.clear(); + + let guard_self = guard(&mut *self, |self_| { + // Clear the partially copied table if a panic occurs, otherwise + // items and growth_left will be out of sync with the contents + // of the table. + self_.clear(); + }); + + unsafe { + for item in source.iter() { + // This may panic. + let item = item.as_ref().clone(); + let hash = hasher(&item); + + // We can use a simpler version of insert() here since: + // - there are no DELETED entries. + // - we know there is enough space in the table. + // - all elements are unique. + let (index, _) = guard_self.table.prepare_insert_slot(hash); + guard_self.bucket(index).write(item); + } + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard_self); + + self.table.items = source.table.items; + self.table.growth_left -= source.table.items; + } else { + self.clone_from(source); + } + } +} + +impl Default for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self::new_in(Default::default()) + } +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator + Clone> Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + if !self.table.is_empty_singleton() { + unsafe { + self.drop_elements(); + self.free_buckets(); + } + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + if !self.table.is_empty_singleton() { + unsafe { + self.drop_elements(); + self.free_buckets(); + } + } + } +} + +impl IntoIterator for RawTable { + type Item = T; + type IntoIter = RawIntoIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> RawIntoIter { + unsafe { + let iter = self.iter(); + self.into_iter_from(iter) + } + } +} + +/// Iterator over a sub-range of a table. Unlike `RawIter` this iterator does +/// not track an item count. +pub(crate) struct RawIterRange { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMask, + + // Pointer to the buckets for the current group. + data: Bucket, + + // Pointer to the next group of control bytes, + // Must be aligned to the group size. + next_ctrl: *const u8, + + // Pointer one past the last control byte of this range. + end: *const u8, +} + +impl RawIterRange { + /// Returns a `RawIterRange` covering a subset of a table. + /// + /// The control byte address must be aligned to the group size. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(ctrl: *const u8, data: Bucket, len: usize) -> Self { + debug_assert_ne!(len, 0); + debug_assert_eq!(ctrl as usize % Group::WIDTH, 0); + let end = ctrl.add(len); + + // Load the first group and advance ctrl to point to the next group + let current_group = Group::load_aligned(ctrl).match_full(); + let next_ctrl = ctrl.add(Group::WIDTH); + + Self { + current_group, + data, + next_ctrl, + end, + } + } + + /// Splits a `RawIterRange` into two halves. + /// + /// Returns `None` if the remaining range is smaller than or equal to the + /// group width. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "rayon")] + pub(crate) fn split(mut self) -> (Self, Option>) { + unsafe { + if self.end <= self.next_ctrl { + // Nothing to split if the group that we are current processing + // is the last one. + (self, None) + } else { + // len is the remaining number of elements after the group that + // we are currently processing. It must be a multiple of the + // group size (small tables are caught by the check above). + let len = offset_from(self.end, self.next_ctrl); + debug_assert_eq!(len % Group::WIDTH, 0); + + // Split the remaining elements into two halves, but round the + // midpoint down in case there is an odd number of groups + // remaining. This ensures that: + // - The tail is at least 1 group long. + // - The split is roughly even considering we still have the + // current group to process. + let mid = (len / 2) & !(Group::WIDTH - 1); + + let tail = Self::new( + self.next_ctrl.add(mid), + self.data.next_n(Group::WIDTH).next_n(mid), + len - mid, + ); + debug_assert_eq!( + self.data.next_n(Group::WIDTH).next_n(mid).ptr, + tail.data.ptr + ); + debug_assert_eq!(self.end, tail.end); + self.end = self.next_ctrl.add(mid); + debug_assert_eq!(self.end.add(Group::WIDTH), tail.next_ctrl); + (self, Some(tail)) + } + } + } +} + +// We make raw iterators unconditionally Send and Sync, and let the PhantomData +// in the actual iterator implementations determine the real Send/Sync bounds. +unsafe impl Send for RawIterRange {} +unsafe impl Sync for RawIterRange {} + +impl Clone for RawIterRange { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + next_ctrl: self.next_ctrl, + current_group: self.current_group, + end: self.end, + } + } +} + +impl Iterator for RawIterRange { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + unsafe { + loop { + if let Some(index) = self.current_group.lowest_set_bit() { + self.current_group = self.current_group.remove_lowest_bit(); + return Some(self.data.next_n(index)); + } + + if self.next_ctrl >= self.end { + return None; + } + + // We might read past self.end up to the next group boundary, + // but this is fine because it only occurs on tables smaller + // than the group size where the trailing control bytes are all + // EMPTY. On larger tables self.end is guaranteed to be aligned + // to the group size (since tables are power-of-two sized). + self.current_group = Group::load_aligned(self.next_ctrl).match_full(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + // We don't have an item count, so just guess based on the range size. + ( + 0, + Some(unsafe { offset_from(self.end, self.next_ctrl) + Group::WIDTH }), + ) + } +} + +impl FusedIterator for RawIterRange {} + +/// Iterator which returns a raw pointer to every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket (unless `reflect_remove` is called). +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator (unless `reflect_insert` is called). +/// - The order in which the iterator yields bucket is unspecified and may +/// change in the future. +pub struct RawIter { + pub(crate) iter: RawIterRange, + items: usize, +} + +impl RawIter { + /// Refresh the iterator so that it reflects a removal from the given bucket. + /// + /// For the iterator to remain valid, this method must be called once + /// for each removed bucket before `next` is called again. + /// + /// This method should be called _before_ the removal is made. It is not necessary to call this + /// method if you are removing an item that this iterator yielded in the past. + #[cfg(feature = "raw")] + pub fn reflect_remove(&mut self, b: &Bucket) { + self.reflect_toggle_full(b, false); + } + + /// Refresh the iterator so that it reflects an insertion into the given bucket. + /// + /// For the iterator to remain valid, this method must be called once + /// for each insert before `next` is called again. + /// + /// This method does not guarantee that an insertion of a bucket witha greater + /// index than the last one yielded will be reflected in the iterator. + /// + /// This method should be called _after_ the given insert is made. + #[cfg(feature = "raw")] + pub fn reflect_insert(&mut self, b: &Bucket) { + self.reflect_toggle_full(b, true); + } + + /// Refresh the iterator so that it reflects a change to the state of the given bucket. + #[cfg(feature = "raw")] + fn reflect_toggle_full(&mut self, b: &Bucket, is_insert: bool) { + unsafe { + if b.as_ptr() > self.iter.data.as_ptr() { + // The iterator has already passed the bucket's group. + // So the toggle isn't relevant to this iterator. + return; + } + + if self.iter.next_ctrl < self.iter.end + && b.as_ptr() <= self.iter.data.next_n(Group::WIDTH).as_ptr() + { + // The iterator has not yet reached the bucket's group. + // We don't need to reload anything, but we do need to adjust the item count. + + if cfg!(debug_assertions) { + // Double-check that the user isn't lying to us by checking the bucket state. + // To do that, we need to find its control byte. We know that self.iter.data is + // at self.iter.next_ctrl - Group::WIDTH, so we work from there: + let offset = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let ctrl = self.iter.next_ctrl.sub(Group::WIDTH).add(offset); + // This method should be called _before_ a removal, or _after_ an insert, + // so in both cases the ctrl byte should indicate that the bucket is full. + assert!(is_full(*ctrl)); + } + + if is_insert { + self.items += 1; + } else { + self.items -= 1; + } + + return; + } + + // The iterator is at the bucket group that the toggled bucket is in. + // We need to do two things: + // + // - Determine if the iterator already yielded the toggled bucket. + // If it did, we're done. + // - Otherwise, update the iterator cached group so that it won't + // yield a to-be-removed bucket, or _will_ yield a to-be-added bucket. + // We'll also need ot update the item count accordingly. + if let Some(index) = self.iter.current_group.lowest_set_bit() { + let next_bucket = self.iter.data.next_n(index); + if b.as_ptr() > next_bucket.as_ptr() { + // The toggled bucket is "before" the bucket the iterator would yield next. We + // therefore don't need to do anything --- the iterator has already passed the + // bucket in question. + // + // The item count must already be correct, since a removal or insert "prior" to + // the iterator's position wouldn't affect the item count. + } else { + // The removed bucket is an upcoming bucket. We need to make sure it does _not_ + // get yielded, and also that it's no longer included in the item count. + // + // NOTE: We can't just reload the group here, both since that might reflect + // inserts we've already passed, and because that might inadvertently unset the + // bits for _other_ removals. If we do that, we'd have to also decrement the + // item count for those other bits that we unset. But the presumably subsequent + // call to reflect for those buckets might _also_ decrement the item count. + // Instead, we _just_ flip the bit for the particular bucket the caller asked + // us to reflect. + let our_bit = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let was_full = self.iter.current_group.flip(our_bit); + debug_assert_ne!(was_full, is_insert); + + if is_insert { + self.items += 1; + } else { + self.items -= 1; + } + + if cfg!(debug_assertions) { + if b.as_ptr() == next_bucket.as_ptr() { + // The removed bucket should no longer be next + debug_assert_ne!(self.iter.current_group.lowest_set_bit(), Some(index)); + } else { + // We should not have changed what bucket comes next. + debug_assert_eq!(self.iter.current_group.lowest_set_bit(), Some(index)); + } + } + } + } else { + // We must have already iterated past the removed item. + } + } + } + + unsafe fn drop_elements(&mut self) { + if mem::needs_drop::() && self.len() != 0 { + for item in self { + item.drop(); + } + } + } +} + +impl Clone for RawIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + items: self.items, + } + } +} + +impl Iterator for RawIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + if let Some(b) = self.iter.next() { + self.items -= 1; + Some(b) + } else { + // We don't check against items == 0 here to allow the + // compiler to optimize away the item count entirely if the + // iterator length is never queried. + debug_assert_eq!(self.items, 0); + None + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } +} + +impl ExactSizeIterator for RawIter {} +impl FusedIterator for RawIter {} + +/// Iterator which consumes a table and returns elements. +pub struct RawIntoIter { + iter: RawIter, + allocation: Option<(NonNull, Layout)>, + marker: PhantomData, + alloc: A, +} + +impl RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawIntoIter where T: Send {} +unsafe impl Sync for RawIntoIter where T: Sync {} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator + Clone> Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout)) = self.allocation { + self.alloc.deallocate(ptr, layout); + } + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout)) = self.allocation { + self.alloc.deallocate(ptr, layout); + } + } + } +} + +impl Iterator for RawIntoIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { Some(self.iter.next()?.read()) } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawIntoIter {} +impl FusedIterator for RawIntoIter {} + +/// Iterator which consumes elements without freeing the table storage. +pub struct RawDrain<'a, T, A: Allocator + Clone = Global> { + iter: RawIter, + + // The table is moved into the iterator for the duration of the drain. This + // ensures that an empty table is left if the drain iterator is leaked + // without dropping. + table: ManuallyDrop>, + orig_table: NonNull>, + + // We don't use a &'a mut RawTable because we want RawDrain to be + // covariant over T. + marker: PhantomData<&'a RawTable>, +} + +impl RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawDrain<'_, T, A> where T: Send {} +unsafe impl Sync for RawDrain<'_, T, A> where T: Sync {} + +impl Drop for RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements. Note that this may panic. + self.iter.drop_elements(); + + // Reset the contents of the table now that all elements have been + // dropped. + self.table.clear_no_drop(); + + // Move the now empty table back to its original location. + self.orig_table + .as_ptr() + .copy_from_nonoverlapping(&*self.table, 1); + } + } +} + +impl Iterator for RawDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { + let item = self.iter.next()?; + Some(item.read()) + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawDrain<'_, T, A> {} +impl FusedIterator for RawDrain<'_, T, A> {} + +/// Iterator over occupied buckets that could match a given hash. +/// +/// In rare cases, the iterator may return a bucket with a different hash. +pub struct RawIterHash<'a, T, A: Allocator + Clone = Global> { + inner: RawIterHashInner<'a, A>, + _marker: PhantomData, +} + +struct RawIterHashInner<'a, A: Allocator + Clone> { + table: &'a RawTableInner, + + // The top 7 bits of the hash. + h2_hash: u8, + + // The sequence of groups to probe in the search. + probe_seq: ProbeSeq, + + group: Group, + + // The elements within the group with a matching h2-hash. + bitmask: BitMaskIter, +} + +impl<'a, T, A: Allocator + Clone> RawIterHash<'a, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn new(table: &'a RawTable, hash: u64) -> Self { + RawIterHash { + inner: RawIterHashInner::new(&table.table, hash), + _marker: PhantomData, + } + } +} +impl<'a, A: Allocator + Clone> RawIterHashInner<'a, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn new(table: &'a RawTableInner, hash: u64) -> Self { + unsafe { + let h2_hash = h2(hash); + let probe_seq = table.probe_seq(hash); + let group = Group::load(table.ctrl(probe_seq.pos)); + let bitmask = group.match_byte(h2_hash).into_iter(); + + RawIterHashInner { + table, + h2_hash, + probe_seq, + group, + bitmask, + } + } + } +} + +impl<'a, T, A: Allocator + Clone> Iterator for RawIterHash<'a, T, A> { + type Item = Bucket; + + fn next(&mut self) -> Option> { + unsafe { + match self.inner.next() { + Some(index) => Some(self.inner.table.bucket(index)), + None => None, + } + } + } +} + +impl<'a, A: Allocator + Clone> Iterator for RawIterHashInner<'a, A> { + type Item = usize; + + fn next(&mut self) -> Option { + unsafe { + loop { + if let Some(bit) = self.bitmask.next() { + let index = (self.probe_seq.pos + bit) & self.table.bucket_mask; + return Some(index); + } + if likely(self.group.match_empty().any_bit_set()) { + return None; + } + self.probe_seq.move_next(self.table.bucket_mask); + self.group = Group::load(self.table.ctrl(self.probe_seq.pos)); + self.bitmask = self.group.match_byte(self.h2_hash).into_iter(); + } + } + } +} + +#[cfg(test)] +mod test_map { + use super::*; + + #[test] + fn rehash() { + let mut table = RawTable::new(); + let hasher = |i: &u64| *i; + for i in 0..100 { + table.insert(i, i, hasher); + } + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + + table.rehash_in_place(hasher); + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/raw/sse2.rs b/third_party/rust/hashbrown/v0_11/crate/src/raw/sse2.rs new file mode 100644 index 000000000000..eed96848584d --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/raw/sse2.rs @@ -0,0 +1,145 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::mem; + +#[cfg(target_arch = "x86")] +use core::arch::x86; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64 as x86; + +pub type BitMaskWord = u16; +pub const BITMASK_STRIDE: usize = 1; +pub const BITMASK_MASK: BitMaskWord = 0xffff; + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a 128-bit SSE value. +#[derive(Copy, Clone)] +pub struct Group(x86::__m128i); + +// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[allow(clippy::items_after_statements)] + pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub unsafe fn load(ptr: *const u8) -> Self { + Group(x86::_mm_loadu_si128(ptr.cast())) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(x86::_mm_load_si128(ptr.cast())) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + x86::_mm_store_si128(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which have + /// the given value. + #[inline] + pub fn match_byte(self, byte: u8) -> BitMask { + #[allow( + clippy::cast_possible_wrap, // byte: u8 as i8 + // byte: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + let cmp = x86::_mm_cmpeq_epi8(self.0, x86::_mm_set1_epi8(byte as i8)); + BitMask(x86::_mm_movemask_epi8(cmp) as u16) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub fn match_empty(self) -> BitMask { + self.match_byte(EMPTY) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub fn match_empty_or_deleted(self) -> BitMask { + #[allow( + // byte: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + // A byte is EMPTY or DELETED iff the high bit is set + BitMask(x86::_mm_movemask_epi8(self.0) as u16) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub fn match_full(&self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + #[allow( + clippy::cast_possible_wrap, // byte: 0x80_u8 as i8 + )] + unsafe { + let zero = x86::_mm_setzero_si128(); + let special = x86::_mm_cmpgt_epi8(zero, self.0); + Group(x86::_mm_or_si128( + special, + x86::_mm_set1_epi8(0x80_u8 as i8), + )) + } + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/rustc_entry.rs b/third_party/rust/hashbrown/v0_11/crate/src/rustc_entry.rs new file mode 100644 index 000000000000..1793c4a600c3 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/rustc_entry.rs @@ -0,0 +1,630 @@ +use self::RustcEntry::*; +use crate::map::{make_insert_hash, Drain, HashMap, IntoIter, Iter, IterMut}; +use crate::raw::{Allocator, Bucket, Global, RawTable}; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.rustc_entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> { + let hash = make_insert_hash(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + RustcEntry::Occupied(RustcOccupiedEntry { + key: Some(key), + elem, + table: &mut self.table, + }) + } else { + // Ideally we would put this in VacantEntry::insert, but Entry is not + // generic over the BuildHasher and adding a generic parameter would be + // a breaking change. + self.reserve(1); + + RustcEntry::Vacant(RustcVacantEntry { + hash, + key, + table: &mut self.table, + }) + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.rustc_entry +pub enum RustcEntry<'a, K, V, A = Global> +where + A: Allocator + Clone, +{ + /// An occupied entry. + Occupied(RustcOccupiedEntry<'a, K, V, A>), + + /// A vacant entry. + Vacant(RustcVacantEntry<'a, K, V, A>), +} + +impl Debug for RustcEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcOccupiedEntry<'a, K, V, A = Global> +where + A: Allocator + Clone, +{ + key: Option, + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, +} + +unsafe impl Send for RustcOccupiedEntry<'_, K, V, A> +where + K: Send, + V: Send, + A: Allocator + Clone + Send, +{ +} +unsafe impl Sync for RustcOccupiedEntry<'_, K, V, A> +where + K: Sync, + V: Sync, + A: Allocator + Clone + Sync, +{ +} + +impl Debug for RustcOccupiedEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcVacantEntry<'a, K, V, A = Global> +where + A: Allocator + Clone, +{ + hash: u64, + key: K, + table: &'a mut RawTable<(K, V), A>, +} + +impl Debug for RustcVacantEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +impl<'a, K, V, A: Allocator + Clone> RustcEntry<'a, K, V, A> { + /// Sets the value of the entry, and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + match self { + Vacant(entry) => entry.insert_entry(value), + Occupied(mut entry) => { + entry.insert(value); + entry + } + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.rustc_entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.rustc_entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K, V: Default, A: Allocator + Clone> RustcEntry<'a, K, V, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.rustc_entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, A: Allocator + Clone> RustcOccupiedEntry<'a, K, V, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem) } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `RustcOccupiedEntry` which may outlive the + /// destruction of the `RustcEntry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same RustcEntry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, mut value: V) -> V { + let old_value = self.get_mut(); + mem::swap(&mut value, old_value); + value + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(Rc::new("Stringthing".to_string()), 15); + /// + /// let my_key = Rc::new("Stringthing".to_string()); + /// + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(my_key) { + /// // Also replace the key with a handle to our other key. + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// } + /// + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let mut known_strings: Vec> = Vec::new(); + /// + /// // Initialise known strings, run program, etc. + /// + /// reclaim_memory(&mut map, &known_strings); + /// + /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { + /// for s in known_strings { + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(s.clone()) { + /// // Replaces the entry's key with our version of it in `known_strings`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap()) + } +} + +impl<'a, K, V, A: Allocator + Clone> RustcVacantEntry<'a, K, V, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `RustcVacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V { + let bucket = self.table.insert_no_grow(self.hash, (self.key, value)); + unsafe { &mut bucket.as_mut().1 } + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + let bucket = self.table.insert_no_grow(self.hash, (self.key, value)); + RustcOccupiedEntry { + key: None, + elem: bucket, + table: self.table, + } + } +} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl Drain<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/scopeguard.rs b/third_party/rust/hashbrown/v0_11/crate/src/scopeguard.rs new file mode 100644 index 000000000000..4e9bf045adbd --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/scopeguard.rs @@ -0,0 +1,49 @@ +// Extracted from the scopeguard crate +use core::ops::{Deref, DerefMut}; + +pub struct ScopeGuard +where + F: FnMut(&mut T), +{ + dropfn: F, + value: T, +} + +#[inline] +pub fn guard(value: T, dropfn: F) -> ScopeGuard +where + F: FnMut(&mut T), +{ + ScopeGuard { dropfn, value } +} + +impl Deref for ScopeGuard +where + F: FnMut(&mut T), +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Drop for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn drop(&mut self) { + (self.dropfn)(&mut self.value) + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/src/set.rs b/third_party/rust/hashbrown/v0_11/crate/src/set.rs new file mode 100644 index 000000000000..d59183b5cadc --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/src/set.rs @@ -0,0 +1,2299 @@ +use crate::TryReserveError; +use alloc::borrow::ToOwned; +use core::borrow::Borrow; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FromIterator, FusedIterator}; +use core::mem; +use core::ops::{BitAnd, BitOr, BitXor, Sub}; + +use super::map::{self, ConsumeAllOnDrop, DefaultHashBuilder, DrainFilterInner, HashMap, Keys}; +use crate::raw::{Allocator, Global}; + +// Future Optimization (FIXME!) +// ============================= +// +// Iteration over zero sized values is a noop. There is no need +// for `bucket.val` in the case of HashSet. I suppose we would need HKT +// to get rid of it properly. + +/// A hash set implemented as a `HashMap` where the value is `()`. +/// +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by +/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, +/// it is important that the following property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// +/// It is a logic error for an item to be modified in such a way that the +/// item's hash, as determined by the [`Hash`] trait, or its equality, as +/// determined by the [`Eq`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or +/// unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashSet` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); +/// +/// // Check for a specific one. +/// if !books.contains("The Winds of Winter") { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove("The Odyssey"); +/// +/// // Iterate over everything. +/// for book in &books { +/// println!("{}", book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`]. This will in the +/// future be implied by [`Eq`]. +/// +/// ``` +/// use hashbrown::HashSet; +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// power: usize, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); +/// +/// // Use derived implementation to print the vikings. +/// for x in &vikings { +/// println!("{:?}", x); +/// } +/// ``` +/// +/// A `HashSet` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashSet; +/// +/// let viking_names: HashSet<&'static str> = +/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); +/// // use the values stored in the set +/// ``` +/// +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`HashMap`]: struct.HashMap.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +pub struct HashSet { + pub(crate) map: HashMap, +} + +impl Clone for HashSet { + fn clone(&self) -> Self { + HashSet { + map: self.map.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.map.clone_from(&source.map); + } +} + +#[cfg(feature = "ahash")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self { + map: HashMap::new(), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self { + map: HashMap::with_capacity(capacity), + } + } +} + +#[cfg(feature = "ahash")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self { + map: HashMap::new_in(alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_in(capacity, alloc), + } + } +} + +impl HashSet { + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + iter: self.map.keys(), + } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(set.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + iter: self.map.drain(), + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let xs = [1,2,3,4,5,6]; + /// let mut set: HashSet = xs.iter().cloned().collect(); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.map.retain(|k, _| f(k)); + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// When the returned DrainedFilter is dropped, any remaining elements that satisfy + /// the predicate are dropped from the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, T, F, A> + where + F: FnMut(&T) -> bool, + { + DrainFilter { + f, + inner: DrainFilterInner { + iter: unsafe { self.map.table.iter() }, + table: &mut self.map.table, + }, + } + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.map.clear() + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hasher: S) -> Self { + Self { + map: HashMap::with_hasher(hasher), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } +} + +impl HashSet +where + A: Allocator + Clone, +{ + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_hasher_in(hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_hasher_in(hasher, alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_and_hasher_in(capacity, hasher, alloc), + } + } + + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let set: HashSet = HashSet::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = set.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + self.map.hasher() + } +} + +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve(additional) + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to_fit(); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit() + } + + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity) + } + + /// Visits the values representing the difference, + /// i.e., the values that are in `self` but not in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet<_> = a.difference(&b).collect(); + /// assert_eq!(diff, [1].iter().collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet<_> = b.difference(&a).collect(); + /// assert_eq!(diff, [4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T, S, A> { + Difference { + iter: self.iter(), + other, + } + } + + /// Visits the values representing the symmetric difference, + /// i.e., the values that are in `self` or in `other` but not in both. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); + /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T, S, A> { + SymmetricDifference { + iter: self.difference(other).chain(other.difference(self)), + } + } + + /// Visits the values representing the intersection, + /// i.e., the values that are both in `self` and `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let intersection: HashSet<_> = a.intersection(&b).collect(); + /// assert_eq!(intersection, [2, 3].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T, S, A> { + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Intersection { + iter: smaller.iter(), + other: larger, + } + } + + /// Visits the values representing the union, + /// i.e., all the values in `self` or `other`, without duplicates. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let union: HashSet<_> = a.union(&b).collect(); + /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T, S, A> { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Union { + iter: larger.iter().chain(smaller.difference(larger)), + } + } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains(&self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + self.map.contains_key(value) + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.get(&2), Some(&2)); + /// assert_eq!(set.get(&4), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self, value: &Q) -> Option<&T> + where + T: Borrow, + Q: Hash + Eq, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.get_key_value(value) { + Some((k, _)) => Some(k), + None => None, + } + } + + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert(&mut self, value: T) -> &T { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(&value) + .or_insert(value, ()) + .0 + } + + /// Inserts an owned copy of the given `value` into the set if it is not + /// present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_owned(pet); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[inline] + pub fn get_or_insert_owned(&mut self, value: &Q) -> &T + where + T: Borrow, + Q: Hash + Eq + ToOwned, + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(value) + .or_insert_with(|| (value.to_owned(), ())) + .0 + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where + T: Borrow, + Q: Hash + Eq, + F: FnOnce(&Q) -> T, + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(value) + .or_insert_with(|| (f(value), ())) + .0 + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut b = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + pub fn is_disjoint(&self, other: &Self) -> bool { + self.iter().all(|v| !other.contains(v)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e., `other` contains at least all the values in `self`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + pub fn is_subset(&self, other: &Self) -> bool { + self.len() <= other.len() && self.iter().all(|v| other.contains(v)) + } + + /// Returns `true` if the set is a superset of another, + /// i.e., `self` contains at least all the values in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sub: HashSet<_> = [1, 2].iter().cloned().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, `true` is returned. + /// + /// If the set did have this value present, `false` is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert(Vec::::new()); + /// + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); + /// set.replace(Vec::with_capacity(10)); + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace(&mut self, value: T) -> Option { + match self.map.entry(value) { + map::Entry::Occupied(occupied) => Some(occupied.replace_key()), + map::Entry::Vacant(vacant) => { + vacant.insert(()); + None + } + } + } + + /// Removes a value from the set. Returns whether the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, value: &Q) -> bool + where + T: Borrow, + Q: Hash + Eq, + { + self.map.remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.take(&2), Some(2)); + /// assert_eq!(set.take(&2), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn take(&mut self, value: &Q) -> Option + where + T: Borrow, + Q: Hash + Eq, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.remove_entry(value) { + Some((k, _)) => Some(k), + None => None, + } + } +} + +impl PartialEq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().all(|key| other.contains(key)) + } +} + +impl Eq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ +} + +impl fmt::Debug for HashSet +where + T: Eq + Hash + fmt::Debug, + S: BuildHasher, + A: Allocator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +impl From> for HashSet +where + A: Allocator + Clone, +{ + fn from(map: HashMap) -> Self { + Self { map } + } +} + +impl FromIterator for HashSet +where + T: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator + Clone, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: I) -> Self { + let mut set = Self::with_hasher_in(Default::default(), Default::default()); + set.extend(iter); + set + } +} + +impl Extend for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.map.extend(iter.into_iter().map(|k| (k, ()))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: T) { + self.map.insert(k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl<'a, T, S, A> Extend<&'a T> for HashSet +where + T: 'a + Eq + Hash + Copy, + S: BuildHasher, + A: Allocator + Clone, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: &'a T) { + self.map.insert(*k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl Default for HashSet +where + S: Default, + A: Default + Allocator + Clone, +{ + /// Creates an empty `HashSet` with the `Default` value for the hasher. + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + map: HashMap::default(), + } + } +} + +impl BitOr<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Clone, +{ + type Output = HashSet; + + /// Returns the union of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &HashSet) -> HashSet { + self.union(rhs).cloned().collect() + } +} + +impl BitAnd<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator + Clone, +{ + type Output = HashSet; + + /// Returns the intersection of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &HashSet) -> HashSet { + self.intersection(rhs).cloned().collect() + } +} + +impl BitXor<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &HashSet) -> HashSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +impl Sub<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &HashSet) -> HashSet { + self.difference(rhs).cloned().collect() + } +} + +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`iter`]: struct.HashSet.html#method.iter +pub struct Iter<'a, K> { + iter: Keys<'a, K, ()>, +} + +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`into_iter`]: struct.HashSet.html#method.into_iter +pub struct IntoIter { + iter: map::IntoIter, +} + +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`drain`]: struct.HashSet.html#method.drain +pub struct Drain<'a, K, A: Allocator + Clone = Global> { + iter: map::Drain<'a, K, (), A>, +} + +/// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. See its +/// documentation for more. +/// +/// [`drain_filter`]: struct.HashSet.html#method.drain_filter +/// [`HashSet`]: struct.HashSet.html +pub struct DrainFilter<'a, K, F, A: Allocator + Clone = Global> +where + F: FnMut(&K) -> bool, +{ + f: F, + inner: DrainFilterInner<'a, K, (), A>, +} + +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`intersection`]: struct.HashSet.html#method.intersection +pub struct Intersection<'a, T, S, A: Allocator + Clone = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`difference`]: struct.HashSet.html#method.difference +pub struct Difference<'a, T, S, A: Allocator + Clone = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference +pub struct SymmetricDifference<'a, T, S, A: Allocator + Clone = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`union`]: struct.HashSet.html#method.union +pub struct Union<'a, T, S, A: Allocator + Clone = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +impl<'a, T, S, A: Allocator + Clone> IntoIterator for &'a HashSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for HashSet { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in &v { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +impl Clone for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} +impl<'a, K> Iterator for Iter<'a, K> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} +impl<'a, K> ExactSizeIterator for Iter<'a, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Iter<'_, K> {} + +impl fmt::Debug for Iter<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Iterator for IntoIter { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for Drain<'_, K, A> { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} +impl ExactSizeIterator for Drain<'_, K, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Drain<'_, K, A> {} + +impl fmt::Debug for Drain<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl<'a, K, F, A: Allocator + Clone> Drop for DrainFilter<'a, K, F, A> +where + F: FnMut(&K) -> bool, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + while let Some(item) = self.next() { + let guard = ConsumeAllOnDrop(self); + drop(item); + mem::forget(guard); + } + } +} + +impl Iterator for DrainFilter<'_, K, F, A> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + let f = &mut self.f; + let (k, _) = self.inner.next(&mut |k, _| f(k))?; + Some(k) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for DrainFilter<'_, K, F, A> where + F: FnMut(&K) -> bool +{ +} + +impl Clone for Intersection<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } +} + +impl fmt::Debug for Intersection<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl FusedIterator for Intersection<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ +} + +impl Clone for Difference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if !self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } +} + +impl FusedIterator for Difference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ +} + +impl fmt::Debug for Difference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for SymmetricDifference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ +} + +impl fmt::Debug for SymmetricDifference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for Union<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl FusedIterator for Union<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ +} + +impl fmt::Debug for Union<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator + Clone, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new, A: Allocator + Clone>( + v: IntoIter<&'static str, A>, + ) -> IntoIter<&'new str, A> { + v + } + fn difference<'a, 'new, A: Allocator + Clone>( + v: Difference<'a, &'static str, DefaultHashBuilder, A>, + ) -> Difference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn symmetric_difference<'a, 'new, A: Allocator + Clone>( + v: SymmetricDifference<'a, &'static str, DefaultHashBuilder, A>, + ) -> SymmetricDifference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn intersection<'a, 'new, A: Allocator + Clone>( + v: Intersection<'a, &'static str, DefaultHashBuilder, A>, + ) -> Intersection<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn union<'a, 'new, A: Allocator + Clone>( + v: Union<'a, &'static str, DefaultHashBuilder, A>, + ) -> Union<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn drain<'new, A: Allocator + Clone>( + d: Drain<'static, &'static str, A>, + ) -> Drain<'new, &'new str, A> { + d + } +} + +#[cfg(test)] +mod test_set { + use super::super::map::DefaultHashBuilder; + use super::HashSet; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); + } + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_map() { + let mut a = crate::HashMap::new(); + a.insert(1, ()); + a.insert(2, ()); + a.insert(3, ()); + a.insert(4, ()); + + let a: HashSet<_> = a.into(); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + + assert_eq!(set.iter().len(), xs.len() - 1); + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); + } + + #[test] + fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{:?}", set); + + assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); + assert_eq!(format!("{:?}", empty), "{}"); + } + + #[test] + fn test_trivial_drain() { + let mut s = HashSet::::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::::new(); + drop(s.drain()); + assert!(s.is_empty()); + } + + #[test] + fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + for _ in &s { + panic!("s should be empty!"); + } + + // reset to try again. + s.extend(1..100); + } + } + + #[test] + fn test_replace() { + use core::hash; + + #[derive(Debug)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); + } + + #[test] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.extend(&[2, 3, 4]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } + + #[test] + fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: HashSet = xs.iter().cloned().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); + } + + #[test] + fn test_drain_filter() { + { + let mut set: HashSet = (0..8).collect(); + let drained = set.drain_filter(|&k| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![0, 2, 4, 6], out); + assert_eq!(set.len(), 4); + } + { + let mut set: HashSet = (0..8).collect(); + drop(set.drain_filter(|&k| k % 2 == 0)); + assert_eq!(set.len(), 4, "Removes non-matching items on drop"); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_SET: HashSet = HashSet::with_hasher(MyHasher); + + let mut set = EMPTY_SET.clone(); + set.insert(19); + assert!(set.contains(&19)); + } + + #[test] + fn rehash_in_place() { + let mut set = HashSet::new(); + + for i in 0..224 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + } +} diff --git a/third_party/rust/hashbrown/v0_11/crate/tests/hasher.rs b/third_party/rust/hashbrown/v0_11/crate/tests/hasher.rs new file mode 100644 index 000000000000..e455e3d3c9a8 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/tests/hasher.rs @@ -0,0 +1,65 @@ +//! Sanity check that alternate hashers work correctly. + +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use std::hash::{BuildHasher, BuildHasherDefault, Hasher}; + +fn check() { + let range = 0..1_000; + + let mut set = HashSet::::default(); + set.extend(range.clone()); + + assert!(!set.contains(&i32::min_value())); + assert!(!set.contains(&(range.start - 1))); + for i in range.clone() { + assert!(set.contains(&i)); + } + assert!(!set.contains(&range.end)); + assert!(!set.contains(&i32::max_value())); +} + +/// Use hashbrown's default hasher. +#[test] +fn default() { + check::(); +} + +/// Use std's default hasher. +#[test] +fn random_state() { + check::(); +} + +/// Use a constant 0 hash. +#[test] +fn zero() { + #[derive(Default)] + struct ZeroHasher; + + impl Hasher for ZeroHasher { + fn finish(&self) -> u64 { + 0 + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} + +/// Use a constant maximum hash. +#[test] +fn max() { + #[derive(Default)] + struct MaxHasher; + + impl Hasher for MaxHasher { + fn finish(&self) -> u64 { + u64::max_value() + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} diff --git a/third_party/rust/hashbrown/v0_11/crate/tests/rayon.rs b/third_party/rust/hashbrown/v0_11/crate/tests/rayon.rs new file mode 100644 index 000000000000..39b47708dde3 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/tests/rayon.rs @@ -0,0 +1,533 @@ +#![cfg(feature = "rayon")] + +#[macro_use] +extern crate lazy_static; + +use hashbrown::{HashMap, HashSet}; +use rayon::iter::{ + IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelExtend, + ParallelIterator, +}; + +macro_rules! assert_eq3 { + ($e1:expr, $e2:expr, $e3:expr) => {{ + assert_eq!($e1, $e2); + assert_eq!($e1, $e3); + assert_eq!($e2, $e3); + }}; +} + +lazy_static! { + static ref MAP_EMPTY: HashMap = HashMap::new(); + static ref MAP: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m.insert('c', 30); + m.insert('e', 50); + m.insert('f', 60); + m.insert('d', 40); + m + }; +} + +#[test] +fn map_seq_par_equivalence_iter_empty() { + let vec_seq = MAP_EMPTY.iter().collect::>(); + let vec_par = MAP_EMPTY.par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter() { + let mut vec_seq = MAP.iter().collect::>(); + let mut vec_par = MAP.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &10), + (&'b', &20), + (&'c', &30), + (&'d', &40), + (&'e', &50), + (&'f', &60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_keys_empty() { + let vec_seq = MAP_EMPTY.keys().collect::>(); + let vec_par = MAP_EMPTY.par_keys().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_keys() { + let mut vec_seq = MAP.keys().collect::>(); + let mut vec_par = MAP.par_keys().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_empty() { + let vec_seq = MAP_EMPTY.values().collect::>(); + let vec_par = MAP_EMPTY.par_values().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values() { + let mut vec_seq = MAP.values().collect::>(); + let mut vec_par = MAP.par_values().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&10, &20, &30, &40, &50, &60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_iter_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.iter_mut().collect::>(); + let vec_par = map2.par_iter_mut().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.iter_mut().collect::>(); + let mut vec_par = map2.par_iter_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &mut 10), + (&'b', &mut 20), + (&'c', &mut 30), + (&'d', &mut 40), + (&'e', &mut 50), + (&'f', &mut 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.values_mut().collect::>(); + let vec_par = map2.par_values_mut().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.values_mut().collect::>(); + let mut vec_par = map2.par_values_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&mut 10, &mut 20, &mut 30, &mut 40, &mut 50, &mut 60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_into_iter_empty() { + let vec_seq = MAP_EMPTY.clone().into_iter().collect::>(); + let vec_par = MAP_EMPTY.clone().into_par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_into_iter() { + let mut vec_seq = MAP.clone().into_iter().collect::>(); + let mut vec_par = MAP.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + ('a', 10), + ('b', 20), + ('c', 30), + ('d', 40), + ('e', 50), + ('f', 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref MAP_VEC_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_VEC: Vec<(char, u32)> = vec![ + ('b', 20), + ('a', 10), + ('c', 30), + ('e', 50), + ('f', 60), + ('d', 40), + ]; +} + +#[test] +fn map_seq_par_equivalence_collect_empty() { + let map_expected = MAP_EMPTY.clone(); + let map_seq = MAP_VEC_EMPTY.clone().into_iter().collect::>(); + let map_par = MAP_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +#[test] +fn map_seq_par_equivalence_collect() { + let map_expected = MAP.clone(); + let map_seq = MAP_VEC.clone().into_iter().collect::>(); + let map_par = MAP_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +lazy_static! { + static ref MAP_EXISTING_EMPTY: HashMap = HashMap::new(); + static ref MAP_EXISTING: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m + }; + static ref MAP_EXTENSION_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_EXTENSION: Vec<(char, u32)> = vec![('c', 30), ('e', 50), ('f', 60), ('d', 40),]; +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashMap::new(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().cloned()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().cloned()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend() { + let expected = MAP_EXTENSION.iter().cloned().collect::>(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION.iter().cloned()); + map_par.par_extend(MAP_EXTENSION.par_iter().cloned()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend_empty() { + let expected = MAP_EXISTING.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().cloned()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().cloned()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend() { + let expected = MAP.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION.iter().cloned()); + map_par.par_extend(MAP_EXTENSION.par_iter().cloned()); + + assert_eq3!(map_seq, map_par, expected); +} + +lazy_static! { + static ref SET_EMPTY: HashSet = HashSet::new(); + static ref SET: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s.insert('c'); + s.insert('e'); + s.insert('f'); + s.insert('d'); + s + }; +} + +#[test] +fn set_seq_par_equivalence_iter_empty() { + let vec_seq = SET_EMPTY.iter().collect::>(); + let vec_par = SET_EMPTY.par_iter().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn set_seq_par_equivalence_iter() { + let mut vec_seq = SET.iter().collect::>(); + let mut vec_par = SET.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn set_seq_par_equivalence_into_iter_empty() { + let vec_seq = SET_EMPTY.clone().into_iter().collect::>(); + let vec_par = SET_EMPTY.clone().into_par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn set_seq_par_equivalence_into_iter() { + let mut vec_seq = SET.clone().into_iter().collect::>(); + let mut vec_par = SET.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = ['a', 'b', 'c', 'd', 'e', 'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref SET_VEC_EMPTY: Vec = vec![]; + static ref SET_VEC: Vec = vec!['b', 'a', 'c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_collect_empty() { + let set_expected = SET_EMPTY.clone(); + let set_seq = SET_VEC_EMPTY.clone().into_iter().collect::>(); + let set_par = SET_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +#[test] +fn set_seq_par_equivalence_collect() { + let set_expected = SET.clone(); + let set_seq = SET_VEC.clone().into_iter().collect::>(); + let set_par = SET_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +lazy_static! { + static ref SET_EXISTING_EMPTY: HashSet = HashSet::new(); + static ref SET_EXISTING: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s + }; + static ref SET_EXTENSION_EMPTY: Vec = vec![]; + static ref SET_EXTENSION: Vec = vec!['c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashSet::new(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().cloned()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().cloned()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend() { + let expected = SET_EXTENSION.iter().cloned().collect::>(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION.iter().cloned()); + set_par.par_extend(SET_EXTENSION.par_iter().cloned()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend_empty() { + let expected = SET_EXISTING.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().cloned()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().cloned()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend() { + let expected = SET.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION.iter().cloned()); + set_par.par_extend(SET_EXTENSION.par_iter().cloned()); + + assert_eq3!(set_seq, set_par, expected); +} + +lazy_static! { + static ref SET_A: HashSet = ['a', 'b', 'c', 'd'].iter().cloned().collect(); + static ref SET_B: HashSet = ['a', 'b', 'e', 'f'].iter().cloned().collect(); + static ref SET_DIFF_AB: HashSet = ['c', 'd'].iter().cloned().collect(); + static ref SET_DIFF_BA: HashSet = ['e', 'f'].iter().cloned().collect(); + static ref SET_SYMM_DIFF_AB: HashSet = ['c', 'd', 'e', 'f'].iter().cloned().collect(); + static ref SET_INTERSECTION_AB: HashSet = ['a', 'b'].iter().cloned().collect(); + static ref SET_UNION_AB: HashSet = + ['a', 'b', 'c', 'd', 'e', 'f'].iter().cloned().collect(); +} + +#[test] +fn set_seq_par_equivalence_difference() { + let diff_ab_seq = SET_A.difference(&*SET_B).cloned().collect::>(); + let diff_ab_par = SET_A + .par_difference(&*SET_B) + .cloned() + .collect::>(); + + assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB); + + let diff_ba_seq = SET_B.difference(&*SET_A).cloned().collect::>(); + let diff_ba_par = SET_B + .par_difference(&*SET_A) + .cloned() + .collect::>(); + + assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA); +} + +#[test] +fn set_seq_par_equivalence_symmetric_difference() { + let symm_diff_ab_seq = SET_A + .symmetric_difference(&*SET_B) + .cloned() + .collect::>(); + let symm_diff_ab_par = SET_A + .par_symmetric_difference(&*SET_B) + .cloned() + .collect::>(); + + assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB); +} + +#[test] +fn set_seq_par_equivalence_intersection() { + let intersection_ab_seq = SET_A.intersection(&*SET_B).cloned().collect::>(); + let intersection_ab_par = SET_A + .par_intersection(&*SET_B) + .cloned() + .collect::>(); + + assert_eq3!( + intersection_ab_seq, + intersection_ab_par, + *SET_INTERSECTION_AB + ); +} + +#[test] +fn set_seq_par_equivalence_union() { + let union_ab_seq = SET_A.union(&*SET_B).cloned().collect::>(); + let union_ab_par = SET_A.par_union(&*SET_B).cloned().collect::>(); + + assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB); +} diff --git a/third_party/rust/hashbrown/v0_11/crate/tests/serde.rs b/third_party/rust/hashbrown/v0_11/crate/tests/serde.rs new file mode 100644 index 000000000000..a642348b3b3b --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/tests/serde.rs @@ -0,0 +1,65 @@ +#![cfg(feature = "serde")] + +use core::hash::BuildHasherDefault; +use fnv::FnvHasher; +use hashbrown::{HashMap, HashSet}; +use serde_test::{assert_tokens, Token}; + +// We use FnvHash for this test because we rely on the ordering +type FnvHashMap = HashMap>; +type FnvHashSet = HashSet>; + +#[test] +fn map_serde_tokens_empty() { + let map = FnvHashMap::::default(); + + assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); +} + +#[test] +fn map_serde_tokens() { + let mut map = FnvHashMap::default(); + map.insert('b', 20); + map.insert('a', 10); + map.insert('c', 30); + + assert_tokens( + &map, + &[ + Token::Map { len: Some(3) }, + Token::Char('a'), + Token::I32(10), + Token::Char('c'), + Token::I32(30), + Token::Char('b'), + Token::I32(20), + Token::MapEnd, + ], + ); +} + +#[test] +fn set_serde_tokens_empty() { + let set = FnvHashSet::::default(); + + assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); +} + +#[test] +fn set_serde_tokens() { + let mut set = FnvHashSet::default(); + set.insert(20); + set.insert(10); + set.insert(30); + + assert_tokens( + &set, + &[ + Token::Seq { len: Some(3) }, + Token::I32(30), + Token::I32(20), + Token::I32(10), + Token::SeqEnd, + ], + ); +} diff --git a/third_party/rust/hashbrown/v0_11/crate/tests/set.rs b/third_party/rust/hashbrown/v0_11/crate/tests/set.rs new file mode 100644 index 000000000000..3fc0717053b4 --- /dev/null +++ b/third_party/rust/hashbrown/v0_11/crate/tests/set.rs @@ -0,0 +1,30 @@ +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng}; + +#[test] +fn test_hashset_insert_remove() { + let mut m: HashSet> = HashSet::new(); + //let num: u32 = 4096; + //let tx: Vec> = (0..num).map(|i| (i..(16 + i)).collect()).collect(); + let seed: [u8; 16] = [ + 130, 220, 246, 217, 111, 124, 221, 189, 190, 234, 121, 93, 67, 95, 100, 43, + ]; + + let rng = &mut SmallRng::from_seed(seed); + let tx: Vec> = (0..4096) + .map(|_| (rng.sample_iter(&Alphanumeric).take(32).collect())) + .collect(); + + for _ in 0..32 { + for i in 0..4096 { + assert_eq!(m.contains(&tx[i].clone()), false); + assert_eq!(m.insert(tx[i].clone()), true); + } + for i in 0..4096 { + println!("removing {} {:?}", i, tx[i]); + assert_eq!(m.remove(&tx[i]), true); + } + } +} diff --git a/third_party/rust/indexmap/v1/BUILD.gn b/third_party/rust/indexmap/v1/BUILD.gn new file mode 100644 index 000000000000..cb69c4d904be --- /dev/null +++ b/third_party/rust/indexmap/v1/BUILD.gn @@ -0,0 +1,60 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# @generated from third_party/rust/BUILD.gn.hbs by tools/crates/gnrt. +# Do not edit! + +import("//build/rust/cargo_crate.gni") + +cargo_crate("lib") { + crate_name = "indexmap" + epoch = "1" + crate_type = "rlib" + + # Only for usage from third-party crates. Add the crate to + # third_party.toml to use it from first-party code. + visibility = [ "//third_party/rust/*" ] + crate_root = "crate/src/lib.rs" + sources = [ + "//brave/third_party/rust/indexmap/v1/crate/benches/bench.rs", + "//brave/third_party/rust/indexmap/v1/crate/benches/faststring.rs", + "//brave/third_party/rust/indexmap/v1/crate/build.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/equivalent.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/lib.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/macros.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/map.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/map/core.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/map/core/raw.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/mutable_keys.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/rayon/map.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/rayon/mod.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/rayon/set.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/rustc.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/serde.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/serde_seq.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/set.rs", + "//brave/third_party/rust/indexmap/v1/crate/src/util.rs", + "//brave/third_party/rust/indexmap/v1/crate/tests/equivalent_trait.rs", + "//brave/third_party/rust/indexmap/v1/crate/tests/macros_full_path.rs", + "//brave/third_party/rust/indexmap/v1/crate/tests/quick.rs", + "//brave/third_party/rust/indexmap/v1/crate/tests/tests.rs", + ] + inputs = [] + + # Unit tests skipped. Generate with --with-tests to include them. + build_native_rust_unit_tests = false + edition = "2018" + cargo_pkg_version = "1.8.1" + cargo_pkg_authors = "bluss, Josh Stone " + cargo_pkg_name = "indexmap" + cargo_pkg_description = "A hash table with consistent order and fast iteration. The indexmap is a hash table where the iteration order of the key-value pairs is independent of the hash values of the keys. It has the usual hash table functionality, it preserves insertion order except after removals, and it allows lookup of its elements by either hash table key or numerical index. A corresponding hash set type is also provided. This crate was initially published under the name ordermap, but it was renamed to indexmap." + library_configs -= [ "//build/config/compiler:chromium_code" ] + library_configs += [ "//build/config/compiler:no_chromium_code" ] + executable_configs -= [ "//build/config/compiler:chromium_code" ] + executable_configs += [ "//build/config/compiler:no_chromium_code" ] + deps = [ "//brave/third_party/rust/hashbrown/v0_11:lib" ] + build_deps = [ "//third_party/rust/autocfg/v1:buildrs_support" ] + build_root = "crate/build.rs" + build_sources = [ "crate/build.rs" ] +} diff --git a/third_party/rust/indexmap/v1/README.chromium b/third_party/rust/indexmap/v1/README.chromium new file mode 100644 index 000000000000..7f00d2e3db7f --- /dev/null +++ b/third_party/rust/indexmap/v1/README.chromium @@ -0,0 +1,16 @@ +Name: indexmap +URL: https://crates.io/crates/indexmap +Description: A hash table with consistent order and fast iteration. + +The indexmap is a hash table where the iteration order of the key-value +pairs is independent of the hash values of the keys. It has the usual +hash table functionality, it preserves insertion order except after +removals, and it allows lookup of its elements by either hash table key +or numerical index. A corresponding hash set type is also provided. + +This crate was initially published under the name ordermap, but it was renamed to +indexmap. +Version: 1.8.1 +Security Critical: no +Shipped: yes +License: Apache 2.0 diff --git a/third_party/rust/indexmap/v1/crate/.cargo_vcs_info.json b/third_party/rust/indexmap/v1/crate/.cargo_vcs_info.json new file mode 100644 index 000000000000..34025e1bd0b7 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "275379c489b483e69d9a61265e9026f42a415219" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/rust/indexmap/v1/crate/.github/workflows/ci.yml b/third_party/rust/indexmap/v1/crate/.github/workflows/ci.yml new file mode 100644 index 000000000000..79cc3d8a3e03 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/.github/workflows/ci.yml @@ -0,0 +1,110 @@ +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +name: Continuous integration + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.49.0 # MSRV + features: + - rust: stable + features: serde + - rust: stable + features: rayon + - rust: stable + features: rustc-rayon + - rust: stable + features: std + - rust: beta + features: + - rust: nightly + bench: test build benchmarks + - rust: nightly + features: test_low_transition_point + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Tests + run: | + cargo build --verbose --features "${{ matrix.features }}" + cargo doc --verbose --features "${{ matrix.features }}" + cargo test --verbose --features "${{ matrix.features }}" + cargo test --release --verbose --features "${{ matrix.features }}" + - name: Tests (serde) + if: matrix.features == 'serde' + run: | + cargo test --verbose -p test-serde + - name: Test run benchmarks + if: matrix.bench != '' + run: cargo test -v --benches + + nostd_build: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.49.0 + target: thumbv6m-none-eabi + - rust: stable + target: thumbv6m-none-eabi + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + target: ${{ matrix.target }} + - name: Tests + run: | + cargo build -vv --target=${{ matrix.target }} + cargo build -v -p test-nostd --target=${{ matrix.target }} + + clippy: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - beta + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + components: clippy + - run: cargo clippy + + miri: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - nightly + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + components: miri + - run: cargo miri test diff --git a/third_party/rust/indexmap/v1/crate/.gitignore b/third_party/rust/indexmap/v1/crate/.gitignore new file mode 100644 index 000000000000..a9d37c560c6a --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/third_party/rust/indexmap/v1/crate/.rustfmt.toml b/third_party/rust/indexmap/v1/crate/.rustfmt.toml new file mode 100644 index 000000000000..32a9786fa1c4 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/.rustfmt.toml @@ -0,0 +1 @@ +edition = "2018" diff --git a/third_party/rust/indexmap/v1/crate/Cargo.toml b/third_party/rust/indexmap/v1/crate/Cargo.toml new file mode 100644 index 000000000000..0b117cdcef88 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/Cargo.toml @@ -0,0 +1,81 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "indexmap" +version = "1.8.1" +authors = ["bluss", "Josh Stone "] +build = "build.rs" +description = "A hash table with consistent order and fast iteration.\n\nThe indexmap is a hash table where the iteration order of the key-value\npairs is independent of the hash values of the keys. It has the usual\nhash table functionality, it preserves insertion order except after\nremovals, and it allows lookup of its elements by either hash table key\nor numerical index. A corresponding hash set type is also provided.\n\nThis crate was initially published under the name ordermap, but it was renamed to\nindexmap.\n" +documentation = "https://docs.rs/indexmap/" +keywords = ["hashmap", "no_std"] +categories = ["data-structures", "no-std"] +license = "Apache-2.0/MIT" +repository = "https://github.com/bluss/indexmap" +[package.metadata.docs.rs] +features = ["serde-1", "rayon"] + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" +[profile.bench] +debug = true + +[lib] +bench = false +[dependencies.hashbrown] +version = "0.11" +features = ["raw"] +default-features = false + +[dependencies.rayon] +version = "1.4.1" +optional = true + +[dependencies.rustc-rayon] +version = "0.3" +optional = true + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false +[dev-dependencies.fnv] +version = "1.0" + +[dev-dependencies.fxhash] +version = "0.2.1" + +[dev-dependencies.itertools] +version = "0.10" + +[dev-dependencies.lazy_static] +version = "1.3" + +[dev-dependencies.quickcheck] +version = "1.0" +default-features = false + +[dev-dependencies.rand] +version = "0.8" +features = ["small_rng"] + +[dev-dependencies.serde_derive] +version = "1.0" +[build-dependencies.autocfg] +version = "1" + +[features] +serde-1 = ["serde"] +std = [] +test_debug = [] +test_low_transition_point = [] diff --git a/third_party/rust/indexmap/v1/crate/Cargo.toml.orig b/third_party/rust/indexmap/v1/crate/Cargo.toml.orig new file mode 100644 index 000000000000..e330b13f286d --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/Cargo.toml.orig @@ -0,0 +1,79 @@ +[package] +name = "indexmap" +edition = "2018" +version = "1.8.1" +authors = [ +"bluss", +"Josh Stone " +] +documentation = "https://docs.rs/indexmap/" +repository = "https://github.com/bluss/indexmap" +license = "Apache-2.0/MIT" +description = """ +A hash table with consistent order and fast iteration. + +The indexmap is a hash table where the iteration order of the key-value +pairs is independent of the hash values of the keys. It has the usual +hash table functionality, it preserves insertion order except after +removals, and it allows lookup of its elements by either hash table key +or numerical index. A corresponding hash set type is also provided. + +This crate was initially published under the name ordermap, but it was renamed to +indexmap. +""" + +keywords = ["hashmap", "no_std"] +categories = ["data-structures", "no-std"] + +build = "build.rs" + +[lib] +bench = false + +[build-dependencies] +autocfg = "1" +[dependencies] +serde = { version = "1.0", optional = true, default-features = false } +rayon = { version = "1.4.1", optional = true } + +# Internal feature, only used when building as part of rustc, +# not part of the stable interface of this crate. +rustc-rayon = { version = "0.3", optional = true } + +[dependencies.hashbrown] +version = "0.11" +default-features = false +features = ["raw"] + +[dev-dependencies] +itertools = "0.10" +rand = {version = "0.8", features = ["small_rng"] } +quickcheck = { version = "1.0", default-features = false } +fnv = "1.0" +lazy_static = "1.3" +fxhash = "0.2.1" +serde_derive = "1.0" + +[features] +# Serialization with serde 1.0 +serde-1 = ["serde"] + +# Force the use of `std`, bypassing target detection. +std = [] + +# for testing only, of course +test_low_transition_point = [] +test_debug = [] + +[profile.bench] +debug = true + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" + +[package.metadata.docs.rs] +features = ["serde-1", "rayon"] + +[workspace] +members = ["test-nostd", "test-serde"] diff --git a/third_party/rust/indexmap/v1/crate/LICENSE-APACHE b/third_party/rust/indexmap/v1/crate/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/indexmap/v1/crate/LICENSE-MIT b/third_party/rust/indexmap/v1/crate/LICENSE-MIT new file mode 100644 index 000000000000..8b8181068b3c --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016--2017 + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/indexmap/v1/crate/README.rst b/third_party/rust/indexmap/v1/crate/README.rst new file mode 100644 index 000000000000..da76a68bfbd1 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/README.rst @@ -0,0 +1,69 @@ +indexmap +======== + +|build_status|_ |crates|_ |docs|_ |rustc|_ + +.. |build_status| image:: https://github.com/bluss/indexmap/workflows/Continuous%20integration/badge.svg?branch=master +.. _build_status: https://github.com/bluss/indexmap/actions + +.. |crates| image:: https://img.shields.io/crates/v/indexmap.svg +.. _crates: https://crates.io/crates/indexmap + +.. |docs| image:: https://docs.rs/indexmap/badge.svg +.. _docs: https://docs.rs/indexmap + +.. |rustc| image:: https://img.shields.io/badge/rust-1.49%2B-orange.svg +.. _rustc: https://img.shields.io/badge/rust-1.49%2B-orange.svg + +A pure-Rust hash table which preserves (in a limited sense) insertion order. + +This crate implements compact map and set data-structures, +where the iteration order of the keys is independent from their hash or +value. It preserves insertion order (except after removals), and it +allows lookup of entries by either hash table key or numerical index. + +Note: this crate was originally released under the name ``ordermap``, +but it was renamed to ``indexmap`` to better reflect its features. + +Background +========== + +This was inspired by Python 3.6's new dict implementation (which remembers +the insertion order and is fast to iterate, and is compact in memory). + +Some of those features were translated to Rust, and some were not. The result +was indexmap, a hash table that has following properties: + +- Order is **independent of hash function** and hash values of keys. +- Fast to iterate. +- Indexed in compact space. +- Preserves insertion order **as long** as you don't call ``.remove()``. +- Uses hashbrown for the inner table, just like Rust's libstd ``HashMap`` does. + +Performance +----------- + +``IndexMap`` derives a couple of performance facts directly from how it is constructed, +which is roughly: + + A raw hash table of key-value indices, and a vector of key-value pairs. + +- Iteration is very fast since it is on the dense key-values. +- Removal is fast since it moves memory areas only in the table, + and uses a single swap in the vector. +- Lookup is fast-ish because the initial 7-bit hash lookup uses SIMD, and indices are + densely stored. Lookup also is slow-ish since the actual key-value pairs are stored + separately. (Visible when cpu caches size is limiting.) + +- In practice, ``IndexMap`` has been tested out as the hashmap in rustc in PR45282_ and + the performance was roughly on par across the whole workload. +- If you want the properties of ``IndexMap``, or its strongest performance points + fits your workload, it might be the best hash table implementation. + +.. _PR45282: https://github.com/rust-lang/rust/pull/45282 + + +Recent Changes +============== + +See `RELEASES.rst <./RELEASES.rst>`_. diff --git a/third_party/rust/indexmap/v1/crate/RELEASES.rst b/third_party/rust/indexmap/v1/crate/RELEASES.rst new file mode 100644 index 000000000000..402724a2fb38 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/RELEASES.rst @@ -0,0 +1,354 @@ +- 1.8.1 + + - The new ``IndexSet::replace_full`` will return the index of the item along + with the replaced value, if any, by @zakcutner in PR 222_. + +.. _222: https://github.com/bluss/indexmap/pull/222 + +- 1.8.0 + + - The new ``IndexMap::into_keys`` and ``IndexMap::into_values`` will consume + the map into keys or values, respectively, matching Rust 1.54's ``HashMap`` + methods, by @taiki-e in PR 195_. + + - More of the iterator types implement ``Debug``, ``ExactSizeIterator``, and + ``FusedIterator``, by @cuviper in PR 196_. + + - ``IndexMap`` and ``IndexSet`` now implement rayon's ``ParallelDrainRange``, + by @cuviper in PR 197_. + + - ``IndexMap::with_hasher`` and ``IndexSet::with_hasher`` are now ``const`` + functions, allowing static maps and sets, by @mwillsey in PR 203_. + + - ``IndexMap`` and ``IndexSet`` now implement ``From`` for arrays, matching + Rust 1.56's implementation for ``HashMap``, by @rouge8 in PR 205_. + + - ``IndexMap`` and ``IndexSet`` now have methods ``sort_unstable_keys``, + ``sort_unstable_by``, ``sorted_unstable_by``, and ``par_*`` equivalents, + which sort in-place without preserving the order of equal items, by + @bhgomes in PR 211_. + +.. _195: https://github.com/bluss/indexmap/pull/195 +.. _196: https://github.com/bluss/indexmap/pull/196 +.. _197: https://github.com/bluss/indexmap/pull/197 +.. _203: https://github.com/bluss/indexmap/pull/203 +.. _205: https://github.com/bluss/indexmap/pull/205 +.. _211: https://github.com/bluss/indexmap/pull/211 + +- 1.7.0 + + - **MSRV**: Rust 1.49 or later is now required. + + - The ``hashbrown`` dependency has been updated to version 0.11. + +- 1.6.2 + + - Fixed to match ``std`` behavior, ``OccupiedEntry::key`` now references the + existing key in the map instead of the lookup key, by @cuviper in PR 170_. + + - The new ``Entry::or_insert_with_key`` matches Rust 1.50's ``Entry`` method, + passing ``&K`` to the callback to create a value, by @cuviper in PR 175_. + +.. _170: https://github.com/bluss/indexmap/pull/170 +.. _175: https://github.com/bluss/indexmap/pull/175 + +- 1.6.1 + + - The new ``serde_seq`` module implements ``IndexMap`` serialization as a + sequence to ensure order is preserved, by @cuviper in PR 158_. + + - New methods on maps and sets work like the ``Vec``/slice methods by the same name: + ``truncate``, ``split_off``, ``first``, ``first_mut``, ``last``, ``last_mut``, and + ``swap_indices``, by @cuviper in PR 160_. + +.. _158: https://github.com/bluss/indexmap/pull/158 +.. _160: https://github.com/bluss/indexmap/pull/160 + +- 1.6.0 + + - **MSRV**: Rust 1.36 or later is now required. + + - The ``hashbrown`` dependency has been updated to version 0.9. + +- 1.5.2 + + - The new "std" feature will force the use of ``std`` for users that explicitly + want the default ``S = RandomState``, bypassing the autodetection added in 1.3.0, + by @cuviper in PR 145_. + +.. _145: https://github.com/bluss/indexmap/pull/145 + +- 1.5.1 + + - Values can now be indexed by their ``usize`` position by @cuviper in PR 132_. + + - Some of the generic bounds have been relaxed to match ``std`` by @cuviper in PR 141_. + + - ``drain`` now accepts any ``R: RangeBounds`` by @cuviper in PR 142_. + +.. _132: https://github.com/bluss/indexmap/pull/132 +.. _141: https://github.com/bluss/indexmap/pull/141 +.. _142: https://github.com/bluss/indexmap/pull/142 + +- 1.5.0 + + - **MSRV**: Rust 1.32 or later is now required. + + - The inner hash table is now based on ``hashbrown`` by @cuviper in PR 131_. + This also completes the method ``reserve`` and adds ``shrink_to_fit``. + + - Add new methods ``get_key_value``, ``remove_entry``, ``swap_remove_entry``, + and ``shift_remove_entry``, by @cuviper in PR 136_ + + - ``Clone::clone_from`` reuses allocations by @cuviper in PR 125_ + + - Add new method ``reverse`` by @linclelinkpart5 in PR 128_ + +.. _125: https://github.com/bluss/indexmap/pull/125 +.. _128: https://github.com/bluss/indexmap/pull/128 +.. _131: https://github.com/bluss/indexmap/pull/131 +.. _136: https://github.com/bluss/indexmap/pull/136 + +- 1.4.0 + + - Add new method ``get_index_of`` by @Thermatrix in PR 115_ and 120_ + + - Fix build script rebuild-if-changed configuration to use "build.rs"; + fixes issue 123_. Fix by @cuviper. + + - Dev-dependencies (rand and quickcheck) have been updated. The crate's tests + now run using Rust 1.32 or later (MSRV for building the crate has not changed). + by @kjeremy and @bluss + +.. _123: https://github.com/bluss/indexmap/issues/123 +.. _115: https://github.com/bluss/indexmap/pull/115 +.. _120: https://github.com/bluss/indexmap/pull/120 + +- 1.3.2 + + - Maintenance update to regenerate the published `Cargo.toml`. + +- 1.3.1 + + - Maintenance update for formatting and ``autocfg`` 1.0. + +- 1.3.0 + + - The deprecation messages in the previous version have been removed. + (The methods have not otherwise changed.) Docs for removal methods have been + improved. + - From Rust 1.36, this crate supports being built **without std**, requiring + ``alloc`` instead. This is enabled automatically when it is detected that + ``std`` is not available. There is no crate feature to enable/disable to + trigger this. The new build-dep ``autocfg`` enables this. + +- 1.2.0 + + - Plain ``.remove()`` now has a deprecation message, it informs the user + about picking one of the removal functions ``swap_remove`` and ``shift_remove`` + which have different performance and order semantics. + Plain ``.remove()`` will not be removed, the warning message and method + will remain until further. + + - Add new method ``shift_remove`` for order preserving removal on the map, + and ``shift_take`` for the corresponding operation on the set. + + - Add methods ``swap_remove``, ``swap_remove_entry`` to ``Entry``. + + - Fix indexset/indexmap to support full paths, like ``indexmap::indexmap!()`` + + - Internal improvements: fix warnings, deprecations and style lints + +- 1.1.0 + + - Added optional feature `"rayon"` that adds parallel iterator support + to `IndexMap` and `IndexSet` using Rayon. This includes all the regular + iterators in parallel versions, and parallel sort. + + - Implemented ``Clone`` for ``map::{Iter, Keys, Values}`` and + ``set::{Difference, Intersection, Iter, SymmetricDifference, Union}`` + + - Implemented ``Debug`` for ``map::{Entry, IntoIter, Iter, Keys, Values}`` and + ``set::{Difference, Intersection, IntoIter, Iter, SymmetricDifference, Union}`` + + - Serde trait ``IntoDeserializer`` are implemented for ``IndexMap`` and ``IndexSet``. + + - Minimum Rust version requirement increased to Rust 1.30 for development builds. + +- 1.0.2 + + - The new methods ``IndexMap::insert_full`` and ``IndexSet::insert_full`` are + both like ``insert`` with the index included in the return value. + + - The new method ``Entry::and_modify`` can be used to modify occupied + entries, matching the new methods of ``std`` maps in Rust 1.26. + + - The new method ``Entry::or_default`` inserts a default value in unoccupied + entries, matching the new methods of ``std`` maps in Rust 1.28. + +- 1.0.1 + + - Document Rust version policy for the crate (see rustdoc) + +- 1.0.0 + + - This is the 1.0 release for ``indexmap``! (the crate and datastructure + formerly known as “ordermap”) + - ``OccupiedEntry::insert`` changed its signature, to use ``&mut self`` for + the method receiver, matching the equivalent method for a standard + ``HashMap``. Thanks to @dtolnay for finding this bug. + - The deprecated old names from ordermap were removed: ``OrderMap``, + ``OrderSet``, ``ordermap!{}``, ``orderset!{}``. Use the new ``IndexMap`` + etc names instead. + +- 0.4.1 + + - Renamed crate to ``indexmap``; the ``ordermap`` crate is now deprecated + and the types ``OrderMap/Set`` now have a deprecation notice. + +- 0.4.0 + + - This is the last release series for this ``ordermap`` under that name, + because the crate is **going to be renamed** to ``indexmap`` (with types + ``IndexMap``, ``IndexSet``) and no change in functionality! + - The map and its associated structs moved into the ``map`` submodule of the + crate, so that the map and set are symmetric + + + The iterators, ``Entry`` and other structs are now under ``ordermap::map::`` + + - Internally refactored ``OrderMap`` so that all the main algorithms + (insertion, lookup, removal etc) that don't use the ``S`` parameter (the + hasher) are compiled without depending on ``S``, which reduces generics bloat. + + - ``Entry`` no longer has a type parameter ``S``, which is just like + the standard ``HashMap``'s entry. + + - Minimum Rust version requirement increased to Rust 1.18 + +- 0.3.5 + + - Documentation improvements + +- 0.3.4 + + - The ``.retain()`` methods for ``OrderMap`` and ``OrderSet`` now + traverse the elements in order, and the retained elements **keep their order** + - Added new methods ``.sort_by()``, ``.sort_keys()`` to ``OrderMap`` and + ``.sort_by()``, ``.sort()`` to ``OrderSet``. These methods allow you to + sort the maps in place efficiently. + +- 0.3.3 + + - Document insertion behaviour better by @lucab + - Updated dependences (no feature changes) by @ignatenkobrain + +- 0.3.2 + + - Add ``OrderSet`` by @cuviper! + - ``OrderMap::drain`` is now (too) a double ended iterator. + +- 0.3.1 + + - In all ordermap iterators, forward the ``collect`` method to the underlying + iterator as well. + - Add crates.io categories. + +- 0.3.0 + + - The methods ``get_pair``, ``get_pair_index`` were both replaced by + ``get_full`` (and the same for the mutable case). + - Method ``swap_remove_pair`` replaced by ``swap_remove_full``. + - Add trait ``MutableKeys`` for opt-in mutable key access. Mutable key access + is only possible through the methods of this extension trait. + - Add new trait ``Equivalent`` for key equivalence. This extends the + ``Borrow`` trait mechanism for ``OrderMap::get`` in a backwards compatible + way, just some minor type inference related issues may become apparent. + See `#10`__ for more information. + - Implement ``Extend<(&K, &V)>`` by @xfix. + +__ https://github.com/bluss/ordermap/pull/10 + +- 0.2.13 + + - Fix deserialization to support custom hashers by @Techcable. + - Add methods ``.index()`` on the entry types by @garro95. + +- 0.2.12 + + - Add methods ``.with_hasher()``, ``.hasher()``. + +- 0.2.11 + + - Support ``ExactSizeIterator`` for the iterators. By @Binero. + - Use ``Box<[Pos]>`` internally, saving a word in the ``OrderMap`` struct. + - Serde support, with crate feature ``"serde-1"``. By @xfix. + +- 0.2.10 + + - Add iterator ``.drain(..)`` by @stevej. + +- 0.2.9 + + - Add method ``.is_empty()`` by @overvenus. + - Implement ``PartialEq, Eq`` by @overvenus. + - Add method ``.sorted_by()``. + +- 0.2.8 + + - Add iterators ``.values()`` and ``.values_mut()``. + - Fix compatibility with 32-bit platforms. + +- 0.2.7 + + - Add ``.retain()``. + +- 0.2.6 + + - Add ``OccupiedEntry::remove_entry`` and other minor entry methods, + so that it now has all the features of ``HashMap``'s entries. + +- 0.2.5 + + - Improved ``.pop()`` slightly. + +- 0.2.4 + + - Improved performance of ``.insert()`` (`#3`__) by @pczarn. + +__ https://github.com/bluss/ordermap/pull/3 + +- 0.2.3 + + - Generalize ``Entry`` for now, so that it works on hashmaps with non-default + hasher. However, there's a lingering compat issue since libstd ``HashMap`` + does not parameterize its entries by the hasher (``S`` typarm). + - Special case some iterator methods like ``.nth()``. + +- 0.2.2 + + - Disable the verbose ``Debug`` impl by default. + +- 0.2.1 + + - Fix doc links and clarify docs. + +- 0.2.0 + + - Add more ``HashMap`` methods & compat with its API. + - Experimental support for ``.entry()`` (the simplest parts of the API). + - Add ``.reserve()`` (placeholder impl). + - Add ``.remove()`` as synonym for ``.swap_remove()``. + - Changed ``.insert()`` to swap value if the entry already exists, and + return ``Option``. + - Experimental support as an *indexed* hash map! Added methods + ``.get_index()``, ``.get_index_mut()``, ``.swap_remove_index()``, + ``.get_pair_index()``, ``.get_pair_index_mut()``. + +- 0.1.2 + + - Implement the 32/32 split idea for ``Pos`` which improves cache utilization + and lookup performance. + +- 0.1.1 + + - Initial release. diff --git a/third_party/rust/indexmap/v1/crate/benches/bench.rs b/third_party/rust/indexmap/v1/crate/benches/bench.rs new file mode 100644 index 000000000000..d6de602dd88c --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/benches/bench.rs @@ -0,0 +1,764 @@ +#![feature(test)] + +extern crate test; +#[macro_use] +extern crate lazy_static; + +use fnv::FnvHasher; +use std::hash::BuildHasherDefault; +use std::hash::Hash; +type FnvBuilder = BuildHasherDefault; + +use test::black_box; +use test::Bencher; + +use indexmap::IndexMap; + +use std::collections::HashMap; +use std::iter::FromIterator; + +use rand::rngs::SmallRng; +use rand::seq::SliceRandom; +use rand::SeedableRng; + +/// Use a consistently seeded Rng for benchmark stability +fn small_rng() -> SmallRng { + let seed = u64::from_le_bytes(*b"indexmap"); + SmallRng::seed_from_u64(seed) +} + +#[bench] +fn new_hashmap(b: &mut Bencher) { + b.iter(|| HashMap::::new()); +} + +#[bench] +fn new_indexmap(b: &mut Bencher) { + b.iter(|| IndexMap::::new()); +} + +#[bench] +fn with_capacity_10e5_hashmap(b: &mut Bencher) { + b.iter(|| HashMap::::with_capacity(10_000)); +} + +#[bench] +fn with_capacity_10e5_indexmap(b: &mut Bencher) { + b.iter(|| IndexMap::::with_capacity(10_000)); +} + +#[bench] +fn insert_hashmap_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_str_10_000(b: &mut Bencher) { + let c = 10_000; + let ss = Vec::from_iter((0..c).map(|x| x.to_string())); + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for key in &ss { + map.insert(&key[..], ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_str_10_000(b: &mut Bencher) { + let c = 10_000; + let ss = Vec::from_iter((0..c).map(|x| x.to_string())); + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for key in &ss { + map.insert(&key[..], ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_int_bigvalue_10_000(b: &mut Bencher) { + let c = 10_000; + let value = [0u64; 10]; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for i in 0..c { + map.insert(i, value); + } + map + }); +} + +#[bench] +fn insert_indexmap_int_bigvalue_10_000(b: &mut Bencher) { + let c = 10_000; + let value = [0u64; 10]; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for i in 0..c { + map.insert(i, value); + } + map + }); +} + +#[bench] +fn insert_hashmap_100_000(b: &mut Bencher) { + let c = 100_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_100_000(b: &mut Bencher) { + let c = 100_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x, ()); + } + map + }); +} + +#[bench] +fn entry_hashmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.entry(x).or_insert(()); + } + map + }); +} + +#[bench] +fn entry_indexmap_150(b: &mut Bencher) { + let c = 150; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.entry(x).or_insert(()); + } + map + }); +} + +#[bench] +fn iter_sum_hashmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| map.keys().sum::()); +} + +#[bench] +fn iter_sum_indexmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| map.keys().sum::()); +} + +#[bench] +fn iter_black_box_hashmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| { + for &key in map.keys() { + black_box(key); + } + }); +} + +#[bench] +fn iter_black_box_indexmap_10_000(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let len = c - c / 10; + for x in 0..len { + map.insert(x, ()); + } + assert_eq!(map.len(), len); + b.iter(|| { + for &key in map.keys() { + black_box(key); + } + }); +} + +fn shuffled_keys(iter: I) -> Vec +where + I: IntoIterator, +{ + let mut v = Vec::from_iter(iter); + let mut rng = small_rng(); + v.shuffle(&mut rng); + v +} + +#[bench] +fn lookup_hashmap_10_000_exist(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in 5000..c { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_hashmap_10_000_noexist(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in c..15000 { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_exist(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in 5000..c { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_noexist(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key, 1); + } + b.iter(|| { + let mut found = 0; + for key in c..15000 { + found += map.get(&key).is_some() as i32; + } + found + }); +} + +// number of items to look up +const LOOKUP_MAP_SIZE: u32 = 100_000_u32; +const LOOKUP_SAMPLE_SIZE: u32 = 5000; +const SORT_MAP_SIZE: usize = 10_000; + +// use lazy_static so that comparison benchmarks use the exact same inputs +lazy_static! { + static ref KEYS: Vec = shuffled_keys(0..LOOKUP_MAP_SIZE); +} + +lazy_static! { + static ref HMAP_100K: HashMap = { + let c = LOOKUP_MAP_SIZE; + let mut map = HashMap::with_capacity(c as usize); + let keys = &*KEYS; + for &key in keys { + map.insert(key, key); + } + map + }; +} + +lazy_static! { + static ref IMAP_100K: IndexMap = { + let c = LOOKUP_MAP_SIZE; + let mut map = IndexMap::with_capacity(c as usize); + let keys = &*KEYS; + for &key in keys { + map.insert(key, key); + } + map + }; +} + +lazy_static! { + static ref IMAP_SORT_U32: IndexMap = { + let mut map = IndexMap::with_capacity(SORT_MAP_SIZE); + for &key in &KEYS[..SORT_MAP_SIZE] { + map.insert(key, key); + } + map + }; +} +lazy_static! { + static ref IMAP_SORT_S: IndexMap = { + let mut map = IndexMap::with_capacity(SORT_MAP_SIZE); + for &key in &KEYS[..SORT_MAP_SIZE] { + map.insert(format!("{:^16x}", &key), String::new()); + } + map + }; +} + +#[bench] +fn lookup_hashmap_100_000_multi(b: &mut Bencher) { + let map = &*HMAP_100K; + b.iter(|| { + let mut found = 0; + for key in 0..LOOKUP_SAMPLE_SIZE { + found += map.get(&key).is_some() as u32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_100_000_multi(b: &mut Bencher) { + let map = &*IMAP_100K; + b.iter(|| { + let mut found = 0; + for key in 0..LOOKUP_SAMPLE_SIZE { + found += map.get(&key).is_some() as u32; + } + found + }); +} + +// inorder: Test looking up keys in the same order as they were inserted +#[bench] +fn lookup_hashmap_100_000_inorder_multi(b: &mut Bencher) { + let map = &*HMAP_100K; + let keys = &*KEYS; + b.iter(|| { + let mut found = 0; + for key in &keys[0..LOOKUP_SAMPLE_SIZE as usize] { + found += map.get(key).is_some() as u32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_100_000_inorder_multi(b: &mut Bencher) { + let map = &*IMAP_100K; + let keys = &*KEYS; + b.iter(|| { + let mut found = 0; + for key in &keys[0..LOOKUP_SAMPLE_SIZE as usize] { + found += map.get(key).is_some() as u32; + } + found + }); +} + +#[bench] +fn lookup_hashmap_100_000_single(b: &mut Bencher) { + let map = &*HMAP_100K; + let mut iter = (0..LOOKUP_MAP_SIZE + LOOKUP_SAMPLE_SIZE).cycle(); + b.iter(|| { + let key = iter.next().unwrap(); + map.get(&key).is_some() + }); +} + +#[bench] +fn lookup_indexmap_100_000_single(b: &mut Bencher) { + let map = &*IMAP_100K; + let mut iter = (0..LOOKUP_MAP_SIZE + LOOKUP_SAMPLE_SIZE).cycle(); + b.iter(|| { + let key = iter.next().unwrap(); + map.get(&key).is_some() + }); +} + +const GROW_SIZE: usize = 100_000; +type GrowKey = u32; + +// Test grow/resize without preallocation +#[bench] +fn grow_fnv_hashmap_100_000(b: &mut Bencher) { + b.iter(|| { + let mut map: HashMap<_, _, FnvBuilder> = HashMap::default(); + for x in 0..GROW_SIZE { + map.insert(x as GrowKey, x as GrowKey); + } + map + }); +} + +#[bench] +fn grow_fnv_indexmap_100_000(b: &mut Bencher) { + b.iter(|| { + let mut map: IndexMap<_, _, FnvBuilder> = IndexMap::default(); + for x in 0..GROW_SIZE { + map.insert(x as GrowKey, x as GrowKey); + } + map + }); +} + +const MERGE: u64 = 10_000; +#[bench] +fn hashmap_merge_simple(b: &mut Bencher) { + let first_map: HashMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: HashMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + b.iter(|| { + let mut merged = first_map.clone(); + merged.extend(second_map.iter().map(|(&k, &v)| (k, v))); + merged + }); +} + +#[bench] +fn hashmap_merge_shuffle(b: &mut Bencher) { + let first_map: HashMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: HashMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + let mut v = Vec::new(); + let mut rng = small_rng(); + b.iter(|| { + let mut merged = first_map.clone(); + v.extend(second_map.iter().map(|(&k, &v)| (k, v))); + v.shuffle(&mut rng); + merged.extend(v.drain(..)); + + merged + }); +} + +#[bench] +fn indexmap_merge_simple(b: &mut Bencher) { + let first_map: IndexMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: IndexMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + b.iter(|| { + let mut merged = first_map.clone(); + merged.extend(second_map.iter().map(|(&k, &v)| (k, v))); + merged + }); +} + +#[bench] +fn indexmap_merge_shuffle(b: &mut Bencher) { + let first_map: IndexMap = (0..MERGE).map(|i| (i, ())).collect(); + let second_map: IndexMap = (MERGE..MERGE * 2).map(|i| (i, ())).collect(); + let mut v = Vec::new(); + let mut rng = small_rng(); + b.iter(|| { + let mut merged = first_map.clone(); + v.extend(second_map.iter().map(|(&k, &v)| (k, v))); + v.shuffle(&mut rng); + merged.extend(v.drain(..)); + + merged + }); +} + +#[bench] +fn swap_remove_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + let mut keys = Vec::from_iter(map.keys().copied()); + let mut rng = small_rng(); + keys.shuffle(&mut rng); + + b.iter(|| { + let mut map = map.clone(); + for key in &keys { + map.swap_remove(key); + } + assert_eq!(map.len(), 0); + map + }); +} + +#[bench] +fn shift_remove_indexmap_100_000_few(b: &mut Bencher) { + let map = IMAP_100K.clone(); + let mut keys = Vec::from_iter(map.keys().copied()); + let mut rng = small_rng(); + keys.shuffle(&mut rng); + keys.truncate(50); + + b.iter(|| { + let mut map = map.clone(); + for key in &keys { + map.shift_remove(key); + } + assert_eq!(map.len(), IMAP_100K.len() - keys.len()); + map + }); +} + +#[bench] +fn shift_remove_indexmap_2_000_full(b: &mut Bencher) { + let mut keys = KEYS[..2_000].to_vec(); + let mut map = IndexMap::with_capacity(keys.len()); + for &key in &keys { + map.insert(key, key); + } + let mut rng = small_rng(); + keys.shuffle(&mut rng); + + b.iter(|| { + let mut map = map.clone(); + for key in &keys { + map.shift_remove(key); + } + assert_eq!(map.len(), 0); + map + }); +} + +#[bench] +fn pop_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + while !map.is_empty() { + map.pop(); + } + assert_eq!(map.len(), 0); + map + }); +} + +#[bench] +fn few_retain_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 7 == 0); + map + }); +} + +#[bench] +fn few_retain_hashmap_100_000(b: &mut Bencher) { + let map = HMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 7 == 0); + map + }); +} + +#[bench] +fn half_retain_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 2 == 0); + map + }); +} + +#[bench] +fn half_retain_hashmap_100_000(b: &mut Bencher) { + let map = HMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 2 == 0); + map + }); +} + +#[bench] +fn many_retain_indexmap_100_000(b: &mut Bencher) { + let map = IMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 100 != 0); + map + }); +} + +#[bench] +fn many_retain_hashmap_100_000(b: &mut Bencher) { + let map = HMAP_100K.clone(); + + b.iter(|| { + let mut map = map.clone(); + map.retain(|k, _| *k % 100 != 0); + map + }); +} + +// simple sort impl for comparison +pub fn simple_sort(m: &mut IndexMap) { + let mut ordered: Vec<_> = m.drain(..).collect(); + ordered.sort_by(|left, right| left.0.cmp(&right.0)); + m.extend(ordered); +} + +#[bench] +fn indexmap_sort_s(b: &mut Bencher) { + let map = IMAP_SORT_S.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + map.sort_keys(); + map + }); +} + +#[bench] +fn indexmap_simple_sort_s(b: &mut Bencher) { + let map = IMAP_SORT_S.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + simple_sort(&mut map); + map + }); +} + +#[bench] +fn indexmap_sort_u32(b: &mut Bencher) { + let map = IMAP_SORT_U32.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + map.sort_keys(); + map + }); +} + +#[bench] +fn indexmap_simple_sort_u32(b: &mut Bencher) { + let map = IMAP_SORT_U32.clone(); + + // there's a map clone there, but it's still useful to profile this + b.iter(|| { + let mut map = map.clone(); + simple_sort(&mut map); + map + }); +} + +// measure the fixed overhead of cloning in sort benchmarks +#[bench] +fn indexmap_clone_for_sort_s(b: &mut Bencher) { + let map = IMAP_SORT_S.clone(); + + b.iter(|| map.clone()); +} + +#[bench] +fn indexmap_clone_for_sort_u32(b: &mut Bencher) { + let map = IMAP_SORT_U32.clone(); + + b.iter(|| map.clone()); +} diff --git a/third_party/rust/indexmap/v1/crate/benches/faststring.rs b/third_party/rust/indexmap/v1/crate/benches/faststring.rs new file mode 100644 index 000000000000..86b7e9cf71d0 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/benches/faststring.rs @@ -0,0 +1,186 @@ +#![feature(test)] + +extern crate test; + +use test::Bencher; + +use indexmap::IndexMap; + +use std::collections::HashMap; +use std::iter::FromIterator; + +use rand::rngs::SmallRng; +use rand::seq::SliceRandom; +use rand::SeedableRng; + +use std::hash::{Hash, Hasher}; + +use std::borrow::Borrow; +use std::ops::Deref; + +/// Use a consistently seeded Rng for benchmark stability +fn small_rng() -> SmallRng { + let seed = u64::from_le_bytes(*b"indexmap"); + SmallRng::seed_from_u64(seed) +} + +#[derive(PartialEq, Eq, Copy, Clone)] +#[repr(transparent)] +pub struct OneShot(pub T); + +impl Hash for OneShot { + fn hash(&self, h: &mut H) { + h.write(self.0.as_bytes()) + } +} + +impl<'a, S> From<&'a S> for &'a OneShot +where + S: AsRef, +{ + fn from(s: &'a S) -> Self { + let s: &str = s.as_ref(); + unsafe { &*(s as *const str as *const OneShot) } + } +} + +impl Hash for OneShot { + fn hash(&self, h: &mut H) { + h.write(self.0.as_bytes()) + } +} + +impl Borrow> for OneShot { + fn borrow(&self) -> &OneShot { + <&OneShot>::from(&self.0) + } +} + +impl Deref for OneShot { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } +} + +fn shuffled_keys(iter: I) -> Vec +where + I: IntoIterator, +{ + let mut v = Vec::from_iter(iter); + let mut rng = small_rng(); + v.shuffle(&mut rng); + v +} + +#[bench] +fn insert_hashmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn insert_hashmap_string_oneshot_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = HashMap::with_capacity(c); + for x in 0..c { + map.insert(OneShot(x.to_string()), ()); + } + map + }); +} + +#[bench] +fn insert_indexmap_string_10_000(b: &mut Bencher) { + let c = 10_000; + b.iter(|| { + let mut map = IndexMap::with_capacity(c); + for x in 0..c { + map.insert(x.to_string(), ()); + } + map + }); +} + +#[bench] +fn lookup_hashmap_10_000_exist_string(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key.to_string(), 1); + } + let lookups = (5000..c).map(|x| x.to_string()).collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_hashmap_10_000_exist_string_oneshot(b: &mut Bencher) { + let c = 10_000; + let mut map = HashMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(OneShot(key.to_string()), 1); + } + let lookups = (5000..c) + .map(|x| OneShot(x.to_string())) + .collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_exist_string(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(key.to_string(), 1); + } + let lookups = (5000..c).map(|x| x.to_string()).collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} + +#[bench] +fn lookup_indexmap_10_000_exist_string_oneshot(b: &mut Bencher) { + let c = 10_000; + let mut map = IndexMap::with_capacity(c); + let keys = shuffled_keys(0..c); + for &key in &keys { + map.insert(OneShot(key.to_string()), 1); + } + let lookups = (5000..c) + .map(|x| OneShot(x.to_string())) + .collect::>(); + b.iter(|| { + let mut found = 0; + for key in &lookups { + found += map.get(key).is_some() as i32; + } + found + }); +} diff --git a/third_party/rust/indexmap/v1/crate/build.rs b/third_party/rust/indexmap/v1/crate/build.rs new file mode 100644 index 000000000000..7c5b6d5e05f3 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/build.rs @@ -0,0 +1,9 @@ +fn main() { + // If "std" is explicitly requested, don't bother probing the target for it. + match std::env::var_os("CARGO_FEATURE_STD") { + Some(_) => autocfg::emit("has_std"), + None => autocfg::new().emit_sysroot_crate("std"), + } + autocfg::new().emit_rustc_version(1, 51); + autocfg::rerun_path("build.rs"); +} diff --git a/third_party/rust/indexmap/v1/crate/src/equivalent.rs b/third_party/rust/indexmap/v1/crate/src/equivalent.rs new file mode 100644 index 000000000000..ad6635ffacae --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/equivalent.rs @@ -0,0 +1,27 @@ +use core::borrow::Borrow; + +/// Key equivalence trait. +/// +/// This trait allows hash table lookup to be customized. +/// It has one blanket implementation that uses the regular `Borrow` solution, +/// just like `HashMap` and `BTreeMap` do, so that you can pass `&str` to lookup +/// into a map with `String` keys and so on. +/// +/// # Contract +/// +/// The implementor **must** hash like `K`, if it is hashable. +pub trait Equivalent { + /// Compare self to `key` and return `true` if they are equal. + fn equivalent(&self, key: &K) -> bool; +} + +impl Equivalent for Q +where + Q: Eq, + K: Borrow, +{ + #[inline] + fn equivalent(&self, key: &K) -> bool { + *self == *key.borrow() + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/lib.rs b/third_party/rust/indexmap/v1/crate/src/lib.rs new file mode 100644 index 000000000000..8c44d7bfc7e2 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/lib.rs @@ -0,0 +1,193 @@ +// We *mostly* avoid unsafe code, but `map::core::raw` allows it to use `RawTable` buckets. +#![deny(unsafe_code)] +#![warn(rust_2018_idioms)] +#![doc(html_root_url = "https://docs.rs/indexmap/1/")] +#![no_std] + +//! [`IndexMap`] is a hash table where the iteration order of the key-value +//! pairs is independent of the hash values of the keys. +//! +//! [`IndexSet`] is a corresponding hash set using the same implementation and +//! with similar properties. +//! +//! [`IndexMap`]: map/struct.IndexMap.html +//! [`IndexSet`]: set/struct.IndexSet.html +//! +//! +//! ### Feature Highlights +//! +//! [`IndexMap`] and [`IndexSet`] are drop-in compatible with the std `HashMap` +//! and `HashSet`, but they also have some features of note: +//! +//! - The ordering semantics (see their documentation for details) +//! - Sorting methods and the [`.pop()`][IndexMap::pop] methods. +//! - The [`Equivalent`] trait, which offers more flexible equality definitions +//! between borrowed and owned versions of keys. +//! - The [`MutableKeys`][map::MutableKeys] trait, which gives opt-in mutable +//! access to hash map keys. +//! +//! ### Alternate Hashers +//! +//! [`IndexMap`] and [`IndexSet`] have a default hasher type `S = RandomState`, +//! just like the standard `HashMap` and `HashSet`, which is resistant to +//! HashDoS attacks but not the most performant. Type aliases can make it easier +//! to use alternate hashers: +//! +//! ``` +//! use fnv::FnvBuildHasher; +//! use fxhash::FxBuildHasher; +//! use indexmap::{IndexMap, IndexSet}; +//! +//! type FnvIndexMap = IndexMap; +//! type FnvIndexSet = IndexSet; +//! +//! type FxIndexMap = IndexMap; +//! type FxIndexSet = IndexSet; +//! +//! let std: IndexSet = (0..100).collect(); +//! let fnv: FnvIndexSet = (0..100).collect(); +//! let fx: FxIndexSet = (0..100).collect(); +//! assert_eq!(std, fnv); +//! assert_eq!(std, fx); +//! ``` +//! +//! ### Rust Version +//! +//! This version of indexmap requires Rust 1.49 or later. +//! +//! The indexmap 1.x release series will use a carefully considered version +//! upgrade policy, where in a later 1.x version, we will raise the minimum +//! required Rust version. +//! +//! ## No Standard Library Targets +//! +//! This crate supports being built without `std`, requiring +//! `alloc` instead. This is enabled automatically when it is detected that +//! `std` is not available. There is no crate feature to enable/disable to +//! trigger this. It can be tested by building for a std-less target. +//! +//! - Creating maps and sets using [`new`][IndexMap::new] and +//! [`with_capacity`][IndexMap::with_capacity] is unavailable without `std`. +//! Use methods [`IndexMap::default`][def], +//! [`with_hasher`][IndexMap::with_hasher], +//! [`with_capacity_and_hasher`][IndexMap::with_capacity_and_hasher] instead. +//! A no-std compatible hasher will be needed as well, for example +//! from the crate `twox-hash`. +//! - Macros [`indexmap!`] and [`indexset!`] are unavailable without `std`. +//! +//! [def]: map/struct.IndexMap.html#impl-Default + +extern crate alloc; + +#[cfg(has_std)] +#[macro_use] +extern crate std; + +use alloc::vec::{self, Vec}; + +#[macro_use] +mod macros; +mod equivalent; +mod mutable_keys; +#[cfg(feature = "serde")] +mod serde; +#[cfg(feature = "serde")] +pub mod serde_seq; +mod util; + +pub mod map; +pub mod set; + +// Placed after `map` and `set` so new `rayon` methods on the types +// are documented after the "normal" methods. +#[cfg(feature = "rayon")] +mod rayon; + +#[cfg(feature = "rustc-rayon")] +mod rustc; + +pub use crate::equivalent::Equivalent; +pub use crate::map::IndexMap; +pub use crate::set::IndexSet; + +// shared private items + +/// Hash value newtype. Not larger than usize, since anything larger +/// isn't used for selecting position anyway. +#[derive(Clone, Copy, Debug, PartialEq)] +struct HashValue(usize); + +impl HashValue { + #[inline(always)] + fn get(self) -> u64 { + self.0 as u64 + } +} + +#[derive(Copy, Debug)] +struct Bucket { + hash: HashValue, + key: K, + value: V, +} + +impl Clone for Bucket +where + K: Clone, + V: Clone, +{ + fn clone(&self) -> Self { + Bucket { + hash: self.hash, + key: self.key.clone(), + value: self.value.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.hash = other.hash; + self.key.clone_from(&other.key); + self.value.clone_from(&other.value); + } +} + +impl Bucket { + // field accessors -- used for `f` instead of closures in `.map(f)` + fn key_ref(&self) -> &K { + &self.key + } + fn value_ref(&self) -> &V { + &self.value + } + fn value_mut(&mut self) -> &mut V { + &mut self.value + } + fn key(self) -> K { + self.key + } + fn value(self) -> V { + self.value + } + fn key_value(self) -> (K, V) { + (self.key, self.value) + } + fn refs(&self) -> (&K, &V) { + (&self.key, &self.value) + } + fn ref_mut(&mut self) -> (&K, &mut V) { + (&self.key, &mut self.value) + } + fn muts(&mut self) -> (&mut K, &mut V) { + (&mut self.key, &mut self.value) + } +} + +trait Entries { + type Entry; + fn into_entries(self) -> Vec; + fn as_entries(&self) -> &[Self::Entry]; + fn as_entries_mut(&mut self) -> &mut [Self::Entry]; + fn with_entries(&mut self, f: F) + where + F: FnOnce(&mut [Self::Entry]); +} diff --git a/third_party/rust/indexmap/v1/crate/src/macros.rs b/third_party/rust/indexmap/v1/crate/src/macros.rs new file mode 100644 index 000000000000..ca26287be984 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/macros.rs @@ -0,0 +1,178 @@ +#[cfg(has_std)] +#[macro_export] +/// Create an `IndexMap` from a list of key-value pairs +/// +/// ## Example +/// +/// ``` +/// use indexmap::indexmap; +/// +/// let map = indexmap!{ +/// "a" => 1, +/// "b" => 2, +/// }; +/// assert_eq!(map["a"], 1); +/// assert_eq!(map["b"], 2); +/// assert_eq!(map.get("c"), None); +/// +/// // "a" is the first key +/// assert_eq!(map.keys().next(), Some(&"a")); +/// ``` +macro_rules! indexmap { + (@single $($x:tt)*) => (()); + (@count $($rest:expr),*) => (<[()]>::len(&[$($crate::indexmap!(@single $rest)),*])); + + ($($key:expr => $value:expr,)+) => { $crate::indexmap!($($key => $value),+) }; + ($($key:expr => $value:expr),*) => { + { + let _cap = $crate::indexmap!(@count $($key),*); + let mut _map = $crate::IndexMap::with_capacity(_cap); + $( + _map.insert($key, $value); + )* + _map + } + }; +} + +#[cfg(has_std)] +#[macro_export] +/// Create an `IndexSet` from a list of values +/// +/// ## Example +/// +/// ``` +/// use indexmap::indexset; +/// +/// let set = indexset!{ +/// "a", +/// "b", +/// }; +/// assert!(set.contains("a")); +/// assert!(set.contains("b")); +/// assert!(!set.contains("c")); +/// +/// // "a" is the first value +/// assert_eq!(set.iter().next(), Some(&"a")); +/// ``` +macro_rules! indexset { + (@single $($x:tt)*) => (()); + (@count $($rest:expr),*) => (<[()]>::len(&[$($crate::indexset!(@single $rest)),*])); + + ($($value:expr,)+) => { $crate::indexset!($($value),+) }; + ($($value:expr),*) => { + { + let _cap = $crate::indexset!(@count $($value),*); + let mut _set = $crate::IndexSet::with_capacity(_cap); + $( + _set.insert($value); + )* + _set + } + }; +} + +// generate all the Iterator methods by just forwarding to the underlying +// self.iter and mapping its element. +macro_rules! iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + // same mapping function for both options and iterators + ($map_elt:expr) => { + fn next(&mut self) -> Option { + self.iter.next().map($map_elt) + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn count(self) -> usize { + self.iter.len() + } + + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n).map($map_elt) + } + + fn last(mut self) -> Option { + self.next_back() + } + + fn collect(self) -> C + where + C: FromIterator, + { + // NB: forwarding this directly to standard iterators will + // allow it to leverage unstable traits like `TrustedLen`. + self.iter.map($map_elt).collect() + } + }; +} + +macro_rules! double_ended_iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + // same mapping function for both options and iterators + ($map_elt:expr) => { + fn next_back(&mut self) -> Option { + self.iter.next_back().map($map_elt) + } + + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n).map($map_elt) + } + }; +} + +// generate `ParallelIterator` methods by just forwarding to the underlying +// self.entries and mapping its elements. +#[cfg(any(feature = "rayon", feature = "rustc-rayon"))] +macro_rules! parallel_iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + ($map_elt:expr) => { + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.entries + .into_par_iter() + .map($map_elt) + .drive_unindexed(consumer) + } + + // NB: This allows indexed collection, e.g. directly into a `Vec`, but the + // underlying iterator must really be indexed. We should remove this if we + // start having tombstones that must be filtered out. + fn opt_len(&self) -> Option { + Some(self.entries.len()) + } + }; +} + +// generate `IndexedParallelIterator` methods by just forwarding to the underlying +// self.entries and mapping its elements. +#[cfg(any(feature = "rayon", feature = "rustc-rayon"))] +macro_rules! indexed_parallel_iterator_methods { + // $map_elt is the mapping function from the underlying iterator's element + ($map_elt:expr) => { + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + self.entries.into_par_iter().map($map_elt).drive(consumer) + } + + fn len(&self) -> usize { + self.entries.len() + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + self.entries + .into_par_iter() + .map($map_elt) + .with_producer(callback) + } + }; +} diff --git a/third_party/rust/indexmap/v1/crate/src/map.rs b/third_party/rust/indexmap/v1/crate/src/map.rs new file mode 100644 index 000000000000..5633047028a3 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/map.rs @@ -0,0 +1,1918 @@ +//! `IndexMap` is a hash table where the iteration order of the key-value +//! pairs is independent of the hash values of the keys. + +mod core; + +pub use crate::mutable_keys::MutableKeys; + +#[cfg(feature = "rayon")] +pub use crate::rayon::map as rayon; + +use crate::vec::{self, Vec}; +use ::core::cmp::Ordering; +use ::core::fmt; +use ::core::hash::{BuildHasher, Hash, Hasher}; +use ::core::iter::{FromIterator, FusedIterator}; +use ::core::ops::{Index, IndexMut, RangeBounds}; +use ::core::slice::{Iter as SliceIter, IterMut as SliceIterMut}; + +#[cfg(has_std)] +use std::collections::hash_map::RandomState; + +use self::core::IndexMapCore; +use crate::equivalent::Equivalent; +use crate::util::third; +use crate::{Bucket, Entries, HashValue}; + +pub use self::core::{Entry, OccupiedEntry, VacantEntry}; + +/// A hash table where the iteration order of the key-value pairs is independent +/// of the hash values of the keys. +/// +/// The interface is closely compatible with the standard `HashMap`, but also +/// has additional features. +/// +/// # Order +/// +/// The key-value pairs have a consistent order that is determined by +/// the sequence of insertion and removal calls on the map. The order does +/// not depend on the keys or the hash function at all. +/// +/// All iterators traverse the map in *the order*. +/// +/// The insertion order is preserved, with **notable exceptions** like the +/// `.remove()` or `.swap_remove()` methods. Methods such as `.sort_by()` of +/// course result in a new order, depending on the sorting order. +/// +/// # Indices +/// +/// The key-value pairs are indexed in a compact range without holes in the +/// range `0..self.len()`. For example, the method `.get_full` looks up the +/// index for a key, and the method `.get_index` looks up the key-value pair by +/// index. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// // count the frequency of each letter in a sentence. +/// let mut letters = IndexMap::new(); +/// for ch in "a short treatise on fungi".chars() { +/// *letters.entry(ch).or_insert(0) += 1; +/// } +/// +/// assert_eq!(letters[&'s'], 2); +/// assert_eq!(letters[&'t'], 3); +/// assert_eq!(letters[&'u'], 1); +/// assert_eq!(letters.get(&'y'), None); +/// ``` +#[cfg(has_std)] +pub struct IndexMap { + pub(crate) core: IndexMapCore, + hash_builder: S, +} +#[cfg(not(has_std))] +pub struct IndexMap { + pub(crate) core: IndexMapCore, + hash_builder: S, +} + +impl Clone for IndexMap +where + K: Clone, + V: Clone, + S: Clone, +{ + fn clone(&self) -> Self { + IndexMap { + core: self.core.clone(), + hash_builder: self.hash_builder.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.core.clone_from(&other.core); + self.hash_builder.clone_from(&other.hash_builder); + } +} + +impl Entries for IndexMap { + type Entry = Bucket; + + #[inline] + fn into_entries(self) -> Vec { + self.core.into_entries() + } + + #[inline] + fn as_entries(&self) -> &[Self::Entry] { + self.core.as_entries() + } + + #[inline] + fn as_entries_mut(&mut self) -> &mut [Self::Entry] { + self.core.as_entries_mut() + } + + fn with_entries(&mut self, f: F) + where + F: FnOnce(&mut [Self::Entry]), + { + self.core.with_entries(f); + } +} + +impl fmt::Debug for IndexMap +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if cfg!(not(feature = "test_debug")) { + f.debug_map().entries(self.iter()).finish() + } else { + // Let the inner `IndexMapCore` print all of its details + f.debug_struct("IndexMap") + .field("core", &self.core) + .finish() + } + } +} + +#[cfg(has_std)] +impl IndexMap { + /// Create a new map. (Does not allocate.) + #[inline] + pub fn new() -> Self { + Self::with_capacity(0) + } + + /// Create a new map with capacity for `n` key-value pairs. (Does not + /// allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + #[inline] + pub fn with_capacity(n: usize) -> Self { + Self::with_capacity_and_hasher(n, <_>::default()) + } +} + +impl IndexMap { + /// Create a new map with capacity for `n` key-value pairs. (Does not + /// allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + #[inline] + pub fn with_capacity_and_hasher(n: usize, hash_builder: S) -> Self { + if n == 0 { + Self::with_hasher(hash_builder) + } else { + IndexMap { + core: IndexMapCore::with_capacity(n), + hash_builder, + } + } + } + + /// Create a new map with `hash_builder`. + /// + /// This function is `const`, so it + /// can be called in `static` contexts. + pub const fn with_hasher(hash_builder: S) -> Self { + IndexMap { + core: IndexMapCore::new(), + hash_builder, + } + } + + /// Computes in **O(1)** time. + pub fn capacity(&self) -> usize { + self.core.capacity() + } + + /// Return a reference to the map's `BuildHasher`. + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Return the number of key-value pairs in the map. + /// + /// Computes in **O(1)** time. + #[inline] + pub fn len(&self) -> usize { + self.core.len() + } + + /// Returns true if the map contains no elements. + /// + /// Computes in **O(1)** time. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Return an iterator over the key-value pairs of the map, in their order + pub fn iter(&self) -> Iter<'_, K, V> { + Iter { + iter: self.as_entries().iter(), + } + } + + /// Return an iterator over the key-value pairs of the map, in their order + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut { + iter: self.as_entries_mut().iter_mut(), + } + } + + /// Return an iterator over the keys of the map, in their order + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { + iter: self.as_entries().iter(), + } + } + + /// Return an owning iterator over the keys of the map, in their order + pub fn into_keys(self) -> IntoKeys { + IntoKeys { + iter: self.into_entries().into_iter(), + } + } + + /// Return an iterator over the values of the map, in their order + pub fn values(&self) -> Values<'_, K, V> { + Values { + iter: self.as_entries().iter(), + } + } + + /// Return an iterator over mutable references to the values of the map, + /// in their order + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut { + iter: self.as_entries_mut().iter_mut(), + } + } + + /// Return an owning iterator over the values of the map, in their order + pub fn into_values(self) -> IntoValues { + IntoValues { + iter: self.into_entries().into_iter(), + } + } + + /// Remove all key-value pairs in the map, while preserving its capacity. + /// + /// Computes in **O(n)** time. + pub fn clear(&mut self) { + self.core.clear(); + } + + /// Shortens the map, keeping the first `len` elements and dropping the rest. + /// + /// If `len` is greater than the map's current length, this has no effect. + pub fn truncate(&mut self, len: usize) { + self.core.truncate(len); + } + + /// Clears the `IndexMap` in the given index range, returning those + /// key-value pairs as a drain iterator. + /// + /// The range may be any type that implements `RangeBounds`, + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To drain the map entirely, use `RangeFull` + /// like `map.drain(..)`. + /// + /// This shifts down all entries following the drained range to fill the + /// gap, and keeps the allocated memory for reuse. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the map. + pub fn drain(&mut self, range: R) -> Drain<'_, K, V> + where + R: RangeBounds, + { + Drain { + iter: self.core.drain(range), + } + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated map containing the elements in the range + /// `[at, len)`. After the call, the original map will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// ***Panics*** if `at > len`. + pub fn split_off(&mut self, at: usize) -> Self + where + S: Clone, + { + Self { + core: self.core.split_off(at), + hash_builder: self.hash_builder.clone(), + } + } +} + +impl IndexMap +where + K: Hash + Eq, + S: BuildHasher, +{ + /// Reserve capacity for `additional` more key-value pairs. + /// + /// Computes in **O(n)** time. + pub fn reserve(&mut self, additional: usize) { + self.core.reserve(additional); + } + + /// Shrink the capacity of the map as much as possible. + /// + /// Computes in **O(n)** time. + pub fn shrink_to_fit(&mut self) { + self.core.shrink_to_fit(); + } + + fn hash(&self, key: &Q) -> HashValue { + let mut h = self.hash_builder.build_hasher(); + key.hash(&mut h); + HashValue(h.finish() as usize) + } + + /// Insert a key-value pair in the map. + /// + /// If an equivalent key already exists in the map: the key remains and + /// retains in its place in the order, its corresponding value is updated + /// with `value` and the older value is returned inside `Some(_)`. + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted, last in order, and `None` is returned. + /// + /// Computes in **O(1)** time (amortized average). + /// + /// See also [`entry`](#method.entry) if you you want to insert *or* modify + /// or if you need to get the index of the corresponding key-value pair. + pub fn insert(&mut self, key: K, value: V) -> Option { + self.insert_full(key, value).1 + } + + /// Insert a key-value pair in the map, and get their index. + /// + /// If an equivalent key already exists in the map: the key remains and + /// retains in its place in the order, its corresponding value is updated + /// with `value` and the older value is returned inside `(index, Some(_))`. + /// + /// If no equivalent key existed in the map: the new key-value pair is + /// inserted, last in order, and `(index, None)` is returned. + /// + /// Computes in **O(1)** time (amortized average). + /// + /// See also [`entry`](#method.entry) if you you want to insert *or* modify + /// or if you need to get the index of the corresponding key-value pair. + pub fn insert_full(&mut self, key: K, value: V) -> (usize, Option) { + let hash = self.hash(&key); + self.core.insert_full(hash, key, value) + } + + /// Get the given key’s corresponding entry in the map for insertion and/or + /// in-place manipulation. + /// + /// Computes in **O(1)** time (amortized average). + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + let hash = self.hash(&key); + self.core.entry(hash, key) + } + + /// Return `true` if an equivalent to `key` exists in the map. + /// + /// Computes in **O(1)** time (average). + pub fn contains_key(&self, key: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.get_index_of(key).is_some() + } + + /// Return a reference to the value stored for `key`, if it is present, + /// else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get(&self, key: &Q) -> Option<&V> + where + Q: Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &self.as_entries()[i]; + Some(&entry.value) + } else { + None + } + } + + /// Return references to the key-value pair stored for `key`, + /// if it is present, else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get_key_value(&self, key: &Q) -> Option<(&K, &V)> + where + Q: Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &self.as_entries()[i]; + Some((&entry.key, &entry.value)) + } else { + None + } + } + + /// Return item index, key and value + pub fn get_full(&self, key: &Q) -> Option<(usize, &K, &V)> + where + Q: Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &self.as_entries()[i]; + Some((i, &entry.key, &entry.value)) + } else { + None + } + } + + /// Return item index, if it exists in the map + /// + /// Computes in **O(1)** time (average). + pub fn get_index_of(&self, key: &Q) -> Option + where + Q: Hash + Equivalent, + { + if self.is_empty() { + None + } else { + let hash = self.hash(key); + self.core.get_index_of(hash, key) + } + } + + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + where + Q: Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some(&mut entry.value) + } else { + None + } + } + + pub fn get_full_mut(&mut self, key: &Q) -> Option<(usize, &K, &mut V)> + where + Q: Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some((i, &entry.key, &mut entry.value)) + } else { + None + } + } + + pub(crate) fn get_full_mut2_impl( + &mut self, + key: &Q, + ) -> Option<(usize, &mut K, &mut V)> + where + Q: Hash + Equivalent, + { + if let Some(i) = self.get_index_of(key) { + let entry = &mut self.as_entries_mut()[i]; + Some((i, &mut entry.key, &mut entry.value)) + } else { + None + } + } + + /// Remove the key-value pair equivalent to `key` and return + /// its value. + /// + /// **NOTE:** This is equivalent to `.swap_remove(key)`, if you need to + /// preserve the order of the keys in the map, use `.shift_remove(key)` + /// instead. + /// + /// Computes in **O(1)** time (average). + pub fn remove(&mut self, key: &Q) -> Option + where + Q: Hash + Equivalent, + { + self.swap_remove(key) + } + + /// Remove and return the key-value pair equivalent to `key`. + /// + /// **NOTE:** This is equivalent to `.swap_remove_entry(key)`, if you need to + /// preserve the order of the keys in the map, use `.shift_remove_entry(key)` + /// instead. + /// + /// Computes in **O(1)** time (average). + pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + Q: Hash + Equivalent, + { + self.swap_remove_entry(key) + } + + /// Remove the key-value pair equivalent to `key` and return + /// its value. + /// + /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(&mut self, key: &Q) -> Option + where + Q: Hash + Equivalent, + { + self.swap_remove_full(key).map(third) + } + + /// Remove and return the key-value pair equivalent to `key`. + /// + /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + Q: Hash + Equivalent, + { + match self.swap_remove_full(key) { + Some((_, key, value)) => Some((key, value)), + None => None, + } + } + + /// Remove the key-value pair equivalent to `key` and return it and + /// the index it had. + /// + /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> + where + Q: Hash + Equivalent, + { + if self.is_empty() { + return None; + } + let hash = self.hash(key); + self.core.swap_remove_full(hash, key) + } + + /// Remove the key-value pair equivalent to `key` and return + /// its value. + /// + /// Like `Vec::remove`, the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(&mut self, key: &Q) -> Option + where + Q: Hash + Equivalent, + { + self.shift_remove_full(key).map(third) + } + + /// Remove and return the key-value pair equivalent to `key`. + /// + /// Like `Vec::remove`, the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(&mut self, key: &Q) -> Option<(K, V)> + where + Q: Hash + Equivalent, + { + match self.shift_remove_full(key) { + Some((_, key, value)) => Some((key, value)), + None => None, + } + } + + /// Remove the key-value pair equivalent to `key` and return it and + /// the index it had. + /// + /// Like `Vec::remove`, the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `key` is not in map. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_full(&mut self, key: &Q) -> Option<(usize, K, V)> + where + Q: Hash + Equivalent, + { + if self.is_empty() { + return None; + } + let hash = self.hash(key); + self.core.shift_remove_full(hash, key) + } + + /// Remove the last key-value pair + /// + /// This preserves the order of the remaining elements. + /// + /// Computes in **O(1)** time (average). + pub fn pop(&mut self) -> Option<(K, V)> { + self.core.pop() + } + + /// Scan through each key-value pair in the map and keep those where the + /// closure `keep` returns `true`. + /// + /// The elements are visited in order, and remaining elements keep their + /// order. + /// + /// Computes in **O(n)** time (average). + pub fn retain(&mut self, mut keep: F) + where + F: FnMut(&K, &mut V) -> bool, + { + self.core.retain_in_order(move |k, v| keep(k, v)); + } + + pub(crate) fn retain_mut(&mut self, keep: F) + where + F: FnMut(&mut K, &mut V) -> bool, + { + self.core.retain_in_order(keep); + } + + /// Sort the map’s key-value pairs by the default ordering of the keys. + /// + /// See [`sort_by`](Self::sort_by) for details. + pub fn sort_keys(&mut self) + where + K: Ord, + { + self.with_entries(move |entries| { + entries.sort_by(move |a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map’s key-value pairs in place using the comparison + /// function `cmp`. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + /// + /// Computes in **O(n log n + c)** time and **O(n)** space where *n* is + /// the length of the map and *c* the capacity. The sort is stable. + pub fn sort_by(&mut self, mut cmp: F) + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + self.with_entries(move |entries| { + entries.sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map and return a by-value iterator of + /// the key-value pairs with the result. + /// + /// The sort is stable. + pub fn sorted_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + let mut entries = self.into_entries(); + entries.sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoIter { + iter: entries.into_iter(), + } + } + + /// Sort the map's key-value pairs by the default ordering of the keys, but + /// may not preserve the order of equal elements. + /// + /// See [`sort_unstable_by`](Self::sort_unstable_by) for details. + pub fn sort_unstable_keys(&mut self) + where + K: Ord, + { + self.with_entries(move |entries| { + entries.sort_unstable_by(move |a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map's key-value pairs in place using the comparison function `cmp`, but + /// may not preserve the order of equal elements. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + /// + /// Computes in **O(n log n + c)** time where *n* is + /// the length of the map and *c* is the capacity. The sort is unstable. + pub fn sort_unstable_by(&mut self, mut cmp: F) + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + self.with_entries(move |entries| { + entries.sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map and return a by-value iterator of + /// the key-value pairs with the result. + /// + /// The sort is unstable. + #[inline] + pub fn sorted_unstable_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&K, &V, &K, &V) -> Ordering, + { + let mut entries = self.into_entries(); + entries.sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoIter { + iter: entries.into_iter(), + } + } + + /// Reverses the order of the map’s key-value pairs in place. + /// + /// Computes in **O(n)** time and **O(1)** space. + pub fn reverse(&mut self) { + self.core.reverse() + } +} + +impl IndexMap { + /// Get a key-value pair by index + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + pub fn get_index(&self, index: usize) -> Option<(&K, &V)> { + self.as_entries().get(index).map(Bucket::refs) + } + + /// Get a key-value pair by index + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + pub fn get_index_mut(&mut self, index: usize) -> Option<(&mut K, &mut V)> { + self.as_entries_mut().get_mut(index).map(Bucket::muts) + } + + /// Get the first key-value pair + /// + /// Computes in **O(1)** time. + pub fn first(&self) -> Option<(&K, &V)> { + self.as_entries().first().map(Bucket::refs) + } + + /// Get the first key-value pair, with mutable access to the value + /// + /// Computes in **O(1)** time. + pub fn first_mut(&mut self) -> Option<(&K, &mut V)> { + self.as_entries_mut().first_mut().map(Bucket::ref_mut) + } + + /// Get the last key-value pair + /// + /// Computes in **O(1)** time. + pub fn last(&self) -> Option<(&K, &V)> { + self.as_entries().last().map(Bucket::refs) + } + + /// Get the last key-value pair, with mutable access to the value + /// + /// Computes in **O(1)** time. + pub fn last_mut(&mut self) -> Option<(&K, &mut V)> { + self.as_entries_mut().last_mut().map(Bucket::ref_mut) + } + + /// Remove the key-value pair by index + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { + self.core.swap_remove_index(index) + } + + /// Remove the key-value pair by index + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Like `Vec::remove`, the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { + self.core.shift_remove_index(index) + } + + /// Swaps the position of two key-value pairs in the map. + /// + /// ***Panics*** if `a` or `b` are out of bounds. + pub fn swap_indices(&mut self, a: usize, b: usize) { + self.core.swap_indices(a, b) + } +} + +/// An iterator over the keys of a `IndexMap`. +/// +/// This `struct` is created by the [`keys`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.IndexMap.html#method.keys +/// [`IndexMap`]: struct.IndexMap.html +pub struct Keys<'a, K, V> { + pub(crate) iter: SliceIter<'a, Bucket>, +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + iterator_methods!(Bucket::key_ref); +} + +impl DoubleEndedIterator for Keys<'_, K, V> { + double_ended_iterator_methods!(Bucket::key_ref); +} + +impl ExactSizeIterator for Keys<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Keys<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + fn clone(&self) -> Self { + Keys { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An owning iterator over the keys of a `IndexMap`. +/// +/// This `struct` is created by the [`into_keys`] method on [`IndexMap`]. +/// See its documentation for more. +/// +/// [`IndexMap`]: struct.IndexMap.html +/// [`into_keys`]: struct.IndexMap.html#method.into_keys +pub struct IntoKeys { + iter: vec::IntoIter>, +} + +impl Iterator for IntoKeys { + type Item = K; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for IntoKeys { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for IntoKeys { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoKeys {} + +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +/// An iterator over the values of a `IndexMap`. +/// +/// This `struct` is created by the [`values`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.IndexMap.html#method.values +/// [`IndexMap`]: struct.IndexMap.html +pub struct Values<'a, K, V> { + iter: SliceIter<'a, Bucket>, +} + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + iterator_methods!(Bucket::value_ref); +} + +impl DoubleEndedIterator for Values<'_, K, V> { + double_ended_iterator_methods!(Bucket::value_ref); +} + +impl ExactSizeIterator for Values<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Values<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + fn clone(&self) -> Self { + Values { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the values of a `IndexMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.IndexMap.html#method.values_mut +/// [`IndexMap`]: struct.IndexMap.html +pub struct ValuesMut<'a, K, V> { + iter: SliceIterMut<'a, Bucket>, +} + +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + iterator_methods!(Bucket::value_mut); +} + +impl DoubleEndedIterator for ValuesMut<'_, K, V> { + double_ended_iterator_methods!(Bucket::value_mut); +} + +impl ExactSizeIterator for ValuesMut<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for ValuesMut<'_, K, V> {} + +// TODO: `impl Debug for ValuesMut` once we have MSRV 1.53 for `slice::IterMut::as_slice` + +/// An owning iterator over the values of a `IndexMap`. +/// +/// This `struct` is created by the [`into_values`] method on [`IndexMap`]. +/// See its documentation for more. +/// +/// [`IndexMap`]: struct.IndexMap.html +/// [`into_values`]: struct.IndexMap.html#method.into_values +pub struct IntoValues { + iter: vec::IntoIter>, +} + +impl Iterator for IntoValues { + type Item = V; + + iterator_methods!(Bucket::value); +} + +impl DoubleEndedIterator for IntoValues { + double_ended_iterator_methods!(Bucket::value); +} + +impl ExactSizeIterator for IntoValues { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoValues {} + +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +/// An iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`iter`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.IndexMap.html#method.iter +/// [`IndexMap`]: struct.IndexMap.html +pub struct Iter<'a, K, V> { + iter: SliceIter<'a, Bucket>, +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + iterator_methods!(Bucket::refs); +} + +impl DoubleEndedIterator for Iter<'_, K, V> { + double_ended_iterator_methods!(Bucket::refs); +} + +impl ExactSizeIterator for Iter<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.IndexMap.html#method.iter_mut +/// [`IndexMap`]: struct.IndexMap.html +pub struct IterMut<'a, K, V> { + iter: SliceIterMut<'a, Bucket>, +} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + iterator_methods!(Bucket::ref_mut); +} + +impl DoubleEndedIterator for IterMut<'_, K, V> { + double_ended_iterator_methods!(Bucket::ref_mut); +} + +impl ExactSizeIterator for IterMut<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IterMut<'_, K, V> {} + +// TODO: `impl Debug for IterMut` once we have MSRV 1.53 for `slice::IterMut::as_slice` + +/// An owning iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`IndexMap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.IndexMap.html#method.into_iter +/// [`IndexMap`]: struct.IndexMap.html +pub struct IntoIter { + pub(crate) iter: vec::IntoIter>, +} + +impl Iterator for IntoIter { + type Item = (K, V); + + iterator_methods!(Bucket::key_value); +} + +impl DoubleEndedIterator for IntoIter { + double_ended_iterator_methods!(Bucket::key_value); +} + +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +/// A draining iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`drain`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.IndexMap.html#method.drain +/// [`IndexMap`]: struct.IndexMap.html +pub struct Drain<'a, K, V> { + pub(crate) iter: vec::Drain<'a, Bucket>, +} + +impl Iterator for Drain<'_, K, V> { + type Item = (K, V); + + iterator_methods!(Bucket::key_value); +} + +impl DoubleEndedIterator for Drain<'_, K, V> { + double_ended_iterator_methods!(Bucket::key_value); +} + +impl ExactSizeIterator for Drain<'_, K, V> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Drain<'_, K, V> {} + +impl fmt::Debug for Drain<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K, V, S> IntoIterator for &'a IndexMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, K, V, S> IntoIterator for &'a mut IndexMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl IntoIterator for IndexMap { + type Item = (K, V); + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + IntoIter { + iter: self.into_entries().into_iter(), + } + } +} + +/// Access `IndexMap` values corresponding to a key. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_uppercase()); +/// } +/// assert_eq!(map["lorem"], "LOREM"); +/// assert_eq!(map["ipsum"], "IPSUM"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// println!("{:?}", map["bar"]); // panics! +/// ``` +impl Index<&Q> for IndexMap +where + Q: Hash + Equivalent, + K: Hash + Eq, + S: BuildHasher, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied `key`. + /// + /// ***Panics*** if `key` is not present in the map. + fn index(&self, key: &Q) -> &V { + self.get(key).expect("IndexMap: key not found") + } +} + +/// Access `IndexMap` values corresponding to a key. +/// +/// Mutable indexing allows changing / updating values of key-value +/// pairs that are already present. +/// +/// You can **not** insert new pairs with index syntax, use `.insert()`. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_string()); +/// } +/// let lorem = &mut map["lorem"]; +/// assert_eq!(lorem, "Lorem"); +/// lorem.retain(char::is_lowercase); +/// assert_eq!(map["lorem"], "orem"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// map["bar"] = 1; // panics! +/// ``` +impl IndexMut<&Q> for IndexMap +where + Q: Hash + Equivalent, + K: Hash + Eq, + S: BuildHasher, +{ + /// Returns a mutable reference to the value corresponding to the supplied `key`. + /// + /// ***Panics*** if `key` is not present in the map. + fn index_mut(&mut self, key: &Q) -> &mut V { + self.get_mut(key).expect("IndexMap: key not found") + } +} + +/// Access `IndexMap` values at indexed positions. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_uppercase()); +/// } +/// assert_eq!(map[0], "LOREM"); +/// assert_eq!(map[1], "IPSUM"); +/// map.reverse(); +/// assert_eq!(map[0], "AMET"); +/// assert_eq!(map[1], "SIT"); +/// map.sort_keys(); +/// assert_eq!(map[0], "AMET"); +/// assert_eq!(map[1], "DOLOR"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// println!("{:?}", map[10]); // panics! +/// ``` +impl Index for IndexMap { + type Output = V; + + /// Returns a reference to the value at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index(&self, index: usize) -> &V { + self.get_index(index) + .expect("IndexMap: index out of bounds") + .1 + } +} + +/// Access `IndexMap` values at indexed positions. +/// +/// Mutable indexing allows changing / updating indexed values +/// that are already present. +/// +/// You can **not** insert new values with index syntax, use `.insert()`. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// map.insert(word.to_lowercase(), word.to_string()); +/// } +/// let lorem = &mut map[0]; +/// assert_eq!(lorem, "Lorem"); +/// lorem.retain(char::is_lowercase); +/// assert_eq!(map["lorem"], "orem"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexMap; +/// +/// let mut map = IndexMap::new(); +/// map.insert("foo", 1); +/// map[10] = 1; // panics! +/// ``` +impl IndexMut for IndexMap { + /// Returns a mutable reference to the value at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index_mut(&mut self, index: usize) -> &mut V { + self.get_index_mut(index) + .expect("IndexMap: index out of bounds") + .1 + } +} + +impl FromIterator<(K, V)> for IndexMap +where + K: Hash + Eq, + S: BuildHasher + Default, +{ + /// Create an `IndexMap` from the sequence of key-value pairs in the + /// iterable. + /// + /// `from_iter` uses the same logic as `extend`. See + /// [`extend`](#method.extend) for more details. + fn from_iter>(iterable: I) -> Self { + let iter = iterable.into_iter(); + let (low, _) = iter.size_hint(); + let mut map = Self::with_capacity_and_hasher(low, <_>::default()); + map.extend(iter); + map + } +} + +#[cfg(all(has_std, rustc_1_51))] +impl From<[(K, V); N]> for IndexMap +where + K: Hash + Eq, +{ + /// # Examples + /// + /// ``` + /// use indexmap::IndexMap; + /// + /// let map1 = IndexMap::from([(1, 2), (3, 4)]); + /// let map2: IndexMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + std::array::IntoIter::new(arr).collect() + } +} + +impl Extend<(K, V)> for IndexMap +where + K: Hash + Eq, + S: BuildHasher, +{ + /// Extend the map with all key-value pairs in the iterable. + /// + /// This is equivalent to calling [`insert`](#method.insert) for each of + /// them in order, which means that for keys that already existed + /// in the map, their value is updated but it keeps the existing order. + /// + /// New keys are inserted in the order they appear in the sequence. If + /// equivalents of a key occur more than once, the last corresponding value + /// prevails. + fn extend>(&mut self, iterable: I) { + // (Note: this is a copy of `std`/`hashbrown`'s reservation logic.) + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iterable.into_iter(); + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + self.reserve(reserve); + iter.for_each(move |(k, v)| { + self.insert(k, v); + }); + } +} + +impl<'a, K, V, S> Extend<(&'a K, &'a V)> for IndexMap +where + K: Hash + Eq + Copy, + V: Copy, + S: BuildHasher, +{ + /// Extend the map with all key-value pairs in the iterable. + /// + /// See the first extend method for more details. + fn extend>(&mut self, iterable: I) { + self.extend(iterable.into_iter().map(|(&key, &value)| (key, value))); + } +} + +impl Default for IndexMap +where + S: Default, +{ + /// Return an empty `IndexMap` + fn default() -> Self { + Self::with_capacity_and_hasher(0, S::default()) + } +} + +impl PartialEq> for IndexMap +where + K: Hash + Eq, + V1: PartialEq, + S1: BuildHasher, + S2: BuildHasher, +{ + fn eq(&self, other: &IndexMap) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl Eq for IndexMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, +{ +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::enumerate; + use std::string::String; + + #[test] + fn it_works() { + let mut map = IndexMap::new(); + assert_eq!(map.is_empty(), true); + map.insert(1, ()); + map.insert(1, ()); + assert_eq!(map.len(), 1); + assert!(map.get(&1).is_some()); + assert_eq!(map.is_empty(), false); + } + + #[test] + fn new() { + let map = IndexMap::::new(); + println!("{:?}", map); + assert_eq!(map.capacity(), 0); + assert_eq!(map.len(), 0); + assert_eq!(map.is_empty(), true); + } + + #[test] + fn insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in enumerate(&insert) { + assert_eq!(map.len(), i); + map.insert(elt, elt); + assert_eq!(map.len(), i + 1); + assert_eq!(map.get(&elt), Some(&elt)); + assert_eq!(map[&elt], elt); + } + println!("{:?}", map); + + for &elt in ¬_present { + assert!(map.get(&elt).is_none()); + } + } + + #[test] + fn insert_full() { + let insert = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in enumerate(&insert) { + assert_eq!(map.len(), i); + let (index, existing) = map.insert_full(elt, elt); + assert_eq!(existing, None); + assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); + assert_eq!(map.len(), i + 1); + } + + let len = map.len(); + for &elt in &present { + let (index, existing) = map.insert_full(elt, elt); + assert_eq!(existing, Some(elt)); + assert_eq!(Some(index), map.get_full(&elt).map(|x| x.0)); + assert_eq!(map.len(), len); + } + } + + #[test] + fn insert_2() { + let mut map = IndexMap::with_capacity(16); + + let mut keys = vec![]; + keys.extend(0..16); + keys.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &keys { + let old_map = map.clone(); + map.insert(i, ()); + for key in old_map.keys() { + if map.get(key).is_none() { + println!("old_map: {:?}", old_map); + println!("map: {:?}", map); + panic!("did not find {} in map", key); + } + } + } + + for &i in &keys { + assert!(map.get(&i).is_some(), "did not find {}", i); + } + } + + #[test] + fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, ()); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().zip(map.keys()) { + assert_eq!(a, b); + } + for (i, k) in (0..insert.len()).zip(map.keys()) { + assert_eq!(map.get_index(i).unwrap().0, k); + } + } + + #[test] + fn grow() { + let insert = [0, 4, 2, 12, 8, 7, 11]; + let not_present = [1, 3, 6, 9, 10]; + let mut map = IndexMap::with_capacity(insert.len()); + + for (i, &elt) in enumerate(&insert) { + assert_eq!(map.len(), i); + map.insert(elt, elt); + assert_eq!(map.len(), i + 1); + assert_eq!(map.get(&elt), Some(&elt)); + assert_eq!(map[&elt], elt); + } + + println!("{:?}", map); + for &elt in &insert { + map.insert(elt * 10, elt); + } + for &elt in &insert { + map.insert(elt * 100, elt); + } + for (i, &elt) in insert.iter().cycle().enumerate().take(100) { + map.insert(elt * 100 + i as i32, elt); + } + println!("{:?}", map); + for &elt in ¬_present { + assert!(map.get(&elt).is_none()); + } + } + + #[test] + fn reserve() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + map.reserve(100); + let capacity = map.capacity(); + assert!(capacity >= 100); + for i in 0..capacity { + assert_eq!(map.len(), i); + map.insert(i, i * i); + assert_eq!(map.len(), i + 1); + assert_eq!(map.capacity(), capacity); + assert_eq!(map.get(&i), Some(&(i * i))); + } + map.insert(capacity, std::usize::MAX); + assert_eq!(map.len(), capacity + 1); + assert!(map.capacity() > capacity); + assert_eq!(map.get(&capacity), Some(&std::usize::MAX)); + } + + #[test] + fn shrink_to_fit() { + let mut map = IndexMap::::new(); + assert_eq!(map.capacity(), 0); + for i in 0..100 { + assert_eq!(map.len(), i); + map.insert(i, i * i); + assert_eq!(map.len(), i + 1); + assert!(map.capacity() >= i + 1); + assert_eq!(map.get(&i), Some(&(i * i))); + map.shrink_to_fit(); + assert_eq!(map.len(), i + 1); + assert_eq!(map.capacity(), i + 1); + assert_eq!(map.get(&i), Some(&(i * i))); + } + } + + #[test] + fn remove() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, elt); + } + + assert_eq!(map.keys().count(), map.len()); + assert_eq!(map.keys().count(), insert.len()); + for (a, b) in insert.iter().zip(map.keys()) { + assert_eq!(a, b); + } + + let remove_fail = [99, 77]; + let remove = [4, 12, 8, 7]; + + for &key in &remove_fail { + assert!(map.swap_remove_full(&key).is_none()); + } + println!("{:?}", map); + for &key in &remove { + //println!("{:?}", map); + let index = map.get_full(&key).unwrap().0; + assert_eq!(map.swap_remove_full(&key), Some((index, key, key))); + } + println!("{:?}", map); + + for key in &insert { + assert_eq!(map.get(key).is_some(), !remove.contains(key)); + } + assert_eq!(map.len(), insert.len() - remove.len()); + assert_eq!(map.keys().count(), insert.len() - remove.len()); + } + + #[test] + fn remove_to_empty() { + let mut map = indexmap! { 0 => 0, 4 => 4, 5 => 5 }; + map.swap_remove(&5).unwrap(); + map.swap_remove(&4).unwrap(); + map.swap_remove(&0).unwrap(); + assert!(map.is_empty()); + } + + #[test] + fn swap_remove_index() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, elt * 2); + } + + let mut vector = insert.to_vec(); + let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; + + // check that the same swap remove sequence on vec and map + // have the same result. + for &rm in remove_sequence { + let out_vec = vector.swap_remove(rm); + let (out_map, _) = map.swap_remove_index(rm).unwrap(); + assert_eq!(out_vec, out_map); + } + assert_eq!(vector.len(), map.len()); + for (a, b) in vector.iter().zip(map.keys()) { + assert_eq!(a, b); + } + } + + #[test] + fn partial_eq_and_eq() { + let mut map_a = IndexMap::new(); + map_a.insert(1, "1"); + map_a.insert(2, "2"); + let mut map_b = map_a.clone(); + assert_eq!(map_a, map_b); + map_b.swap_remove(&1); + assert_ne!(map_a, map_b); + + let map_c: IndexMap<_, String> = map_b.into_iter().map(|(k, v)| (k, v.into())).collect(); + assert_ne!(map_a, map_c); + assert_ne!(map_c, map_a); + } + + #[test] + fn extend() { + let mut map = IndexMap::new(); + map.extend(vec![(&1, &2), (&3, &4)]); + map.extend(vec![(5, 6)]); + assert_eq!( + map.into_iter().collect::>(), + vec![(1, 2), (3, 4), (5, 6)] + ); + } + + #[test] + fn entry() { + let mut map = IndexMap::new(); + + map.insert(1, "1"); + map.insert(2, "2"); + { + let e = map.entry(3); + assert_eq!(e.index(), 2); + let e = e.or_insert("3"); + assert_eq!(e, &"3"); + } + + let e = map.entry(2); + assert_eq!(e.index(), 1); + assert_eq!(e.key(), &2); + match e { + Entry::Occupied(ref e) => assert_eq!(e.get(), &"2"), + Entry::Vacant(_) => panic!(), + } + assert_eq!(e.or_insert("4"), &"2"); + } + + #[test] + fn entry_and_modify() { + let mut map = IndexMap::new(); + + map.insert(1, "1"); + map.entry(1).and_modify(|x| *x = "2"); + assert_eq!(Some(&"2"), map.get(&1)); + + map.entry(2).and_modify(|x| *x = "doesn't exist"); + assert_eq!(None, map.get(&2)); + } + + #[test] + fn entry_or_default() { + let mut map = IndexMap::new(); + + #[derive(Debug, PartialEq)] + enum TestEnum { + DefaultValue, + NonDefaultValue, + } + + impl Default for TestEnum { + fn default() -> Self { + TestEnum::DefaultValue + } + } + + map.insert(1, TestEnum::NonDefaultValue); + assert_eq!(&mut TestEnum::NonDefaultValue, map.entry(1).or_default()); + + assert_eq!(&mut TestEnum::DefaultValue, map.entry(2).or_default()); + } + + #[test] + fn occupied_entry_key() { + // These keys match hash and equality, but their addresses are distinct. + let (k1, k2) = (&mut 1, &mut 1); + let k1_ptr = k1 as *const i32; + let k2_ptr = k2 as *const i32; + assert_ne!(k1_ptr, k2_ptr); + + let mut map = IndexMap::new(); + map.insert(k1, "value"); + match map.entry(k2) { + Entry::Occupied(ref e) => { + // `OccupiedEntry::key` should reference the key in the map, + // not the key that was used to find the entry. + let ptr = *e.key() as *const i32; + assert_eq!(ptr, k1_ptr); + assert_ne!(ptr, k2_ptr); + } + Entry::Vacant(_) => panic!(), + } + } + + #[test] + fn keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let keys: Vec = map.into_keys().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: IndexMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value *= 2 + } + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_iter().collect(); + let values: Vec = map.into_values().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + #[cfg(all(has_std, rustc_1_51))] + fn from_array() { + let map = IndexMap::from([(1, 2), (3, 4)]); + let mut expected = IndexMap::new(); + expected.insert(1, 2); + expected.insert(3, 4); + + assert_eq!(map, expected) + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/map/core.rs b/third_party/rust/indexmap/v1/crate/src/map/core.rs new file mode 100644 index 000000000000..bfd571d9ae96 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/map/core.rs @@ -0,0 +1,661 @@ +//! This is the core implementation that doesn't depend on the hasher at all. +//! +//! The methods of `IndexMapCore` don't use any Hash properties of K. +//! +//! It's cleaner to separate them out, then the compiler checks that we are not +//! using Hash at all in these methods. +//! +//! However, we should probably not let this show in the public API or docs. + +mod raw; + +use hashbrown::raw::RawTable; + +use crate::vec::{Drain, Vec}; +use core::cmp; +use core::fmt; +use core::mem::replace; +use core::ops::RangeBounds; + +use crate::equivalent::Equivalent; +use crate::util::{enumerate, simplify_range}; +use crate::{Bucket, Entries, HashValue}; + +/// Core of the map that does not depend on S +pub(crate) struct IndexMapCore { + /// indices mapping from the entry hash to its index. + indices: RawTable, + /// entries is a dense vec of entries in their order. + entries: Vec>, +} + +#[inline(always)] +fn get_hash(entries: &[Bucket]) -> impl Fn(&usize) -> u64 + '_ { + move |&i| entries[i].hash.get() +} + +#[inline] +fn equivalent<'a, K, V, Q: ?Sized + Equivalent>( + key: &'a Q, + entries: &'a [Bucket], +) -> impl Fn(&usize) -> bool + 'a { + move |&i| Q::equivalent(key, &entries[i].key) +} + +#[inline] +fn erase_index(table: &mut RawTable, hash: HashValue, index: usize) { + table.erase_entry(hash.get(), move |&i| i == index); +} + +#[inline] +fn update_index(table: &mut RawTable, hash: HashValue, old: usize, new: usize) { + let index = table + .get_mut(hash.get(), move |&i| i == old) + .expect("index not found"); + *index = new; +} + +impl Clone for IndexMapCore +where + K: Clone, + V: Clone, +{ + fn clone(&self) -> Self { + let indices = self.indices.clone(); + let mut entries = Vec::with_capacity(indices.capacity()); + entries.clone_from(&self.entries); + IndexMapCore { indices, entries } + } + + fn clone_from(&mut self, other: &Self) { + let hasher = get_hash(&other.entries); + self.indices.clone_from_with_hasher(&other.indices, hasher); + if self.entries.capacity() < other.entries.len() { + // If we must resize, match the indices capacity + self.reserve_entries(); + } + self.entries.clone_from(&other.entries); + } +} + +impl fmt::Debug for IndexMapCore +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IndexMapCore") + .field("indices", &raw::DebugIndices(&self.indices)) + .field("entries", &self.entries) + .finish() + } +} + +impl Entries for IndexMapCore { + type Entry = Bucket; + + #[inline] + fn into_entries(self) -> Vec { + self.entries + } + + #[inline] + fn as_entries(&self) -> &[Self::Entry] { + &self.entries + } + + #[inline] + fn as_entries_mut(&mut self) -> &mut [Self::Entry] { + &mut self.entries + } + + fn with_entries(&mut self, f: F) + where + F: FnOnce(&mut [Self::Entry]), + { + f(&mut self.entries); + self.rebuild_hash_table(); + } +} + +impl IndexMapCore { + #[inline] + pub(crate) const fn new() -> Self { + IndexMapCore { + indices: RawTable::new(), + entries: Vec::new(), + } + } + + #[inline] + pub(crate) fn with_capacity(n: usize) -> Self { + IndexMapCore { + indices: RawTable::with_capacity(n), + entries: Vec::with_capacity(n), + } + } + + #[inline] + pub(crate) fn len(&self) -> usize { + self.indices.len() + } + + #[inline] + pub(crate) fn capacity(&self) -> usize { + cmp::min(self.indices.capacity(), self.entries.capacity()) + } + + pub(crate) fn clear(&mut self) { + self.indices.clear(); + self.entries.clear(); + } + + pub(crate) fn truncate(&mut self, len: usize) { + if len < self.len() { + self.erase_indices(len, self.entries.len()); + self.entries.truncate(len); + } + } + + pub(crate) fn drain(&mut self, range: R) -> Drain<'_, Bucket> + where + R: RangeBounds, + { + let range = simplify_range(range, self.entries.len()); + self.erase_indices(range.start, range.end); + self.entries.drain(range) + } + + #[cfg(feature = "rayon")] + pub(crate) fn par_drain(&mut self, range: R) -> rayon::vec::Drain<'_, Bucket> + where + K: Send, + V: Send, + R: RangeBounds, + { + use rayon::iter::ParallelDrainRange; + let range = simplify_range(range, self.entries.len()); + self.erase_indices(range.start, range.end); + self.entries.par_drain(range) + } + + pub(crate) fn split_off(&mut self, at: usize) -> Self { + assert!(at <= self.entries.len()); + self.erase_indices(at, self.entries.len()); + let entries = self.entries.split_off(at); + + let mut indices = RawTable::with_capacity(entries.len()); + for (i, entry) in enumerate(&entries) { + indices.insert_no_grow(entry.hash.get(), i); + } + Self { indices, entries } + } + + /// Reserve capacity for `additional` more key-value pairs. + pub(crate) fn reserve(&mut self, additional: usize) { + self.indices.reserve(additional, get_hash(&self.entries)); + self.reserve_entries(); + } + + /// Reserve entries capacity to match the indices + fn reserve_entries(&mut self) { + let additional = self.indices.capacity() - self.entries.len(); + self.entries.reserve_exact(additional); + } + + /// Shrink the capacity of the map as much as possible. + pub(crate) fn shrink_to_fit(&mut self) { + self.indices.shrink_to(0, get_hash(&self.entries)); + self.entries.shrink_to_fit(); + } + + /// Remove the last key-value pair + pub(crate) fn pop(&mut self) -> Option<(K, V)> { + if let Some(entry) = self.entries.pop() { + let last = self.entries.len(); + erase_index(&mut self.indices, entry.hash, last); + Some((entry.key, entry.value)) + } else { + None + } + } + + /// Append a key-value pair, *without* checking whether it already exists, + /// and return the pair's new index. + fn push(&mut self, hash: HashValue, key: K, value: V) -> usize { + let i = self.entries.len(); + self.indices.insert(hash.get(), i, get_hash(&self.entries)); + if i == self.entries.capacity() { + // Reserve our own capacity synced to the indices, + // rather than letting `Vec::push` just double it. + self.reserve_entries(); + } + self.entries.push(Bucket { hash, key, value }); + i + } + + /// Return the index in `entries` where an equivalent key can be found + pub(crate) fn get_index_of(&self, hash: HashValue, key: &Q) -> Option + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + self.indices.get(hash.get(), eq).copied() + } + + pub(crate) fn insert_full(&mut self, hash: HashValue, key: K, value: V) -> (usize, Option) + where + K: Eq, + { + match self.get_index_of(hash, &key) { + Some(i) => (i, Some(replace(&mut self.entries[i].value, value))), + None => (self.push(hash, key, value), None), + } + } + + /// Remove an entry by shifting all entries that follow it + pub(crate) fn shift_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + match self.indices.remove_entry(hash.get(), eq) { + Some(index) => { + let (key, value) = self.shift_remove_finish(index); + Some((index, key, value)) + } + None => None, + } + } + + /// Remove an entry by shifting all entries that follow it + pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { + match self.entries.get(index) { + Some(entry) => { + erase_index(&mut self.indices, entry.hash, index); + Some(self.shift_remove_finish(index)) + } + None => None, + } + } + + /// Remove an entry by shifting all entries that follow it + /// + /// The index should already be removed from `self.indices`. + fn shift_remove_finish(&mut self, index: usize) -> (K, V) { + // use Vec::remove, but then we need to update the indices that point + // to all of the other entries that have to move + let entry = self.entries.remove(index); + + // correct indices that point to the entries that followed the removed entry. + // use a heuristic between a full sweep vs. a `find()` for every shifted item. + let raw_capacity = self.indices.buckets(); + let shifted_entries = &self.entries[index..]; + if shifted_entries.len() > raw_capacity / 2 { + // shift all indices greater than `index` + for i in self.indices_mut() { + if *i > index { + *i -= 1; + } + } + } else { + // find each following entry to shift its index + for (i, entry) in (index + 1..).zip(shifted_entries) { + update_index(&mut self.indices, entry.hash, i, i - 1); + } + } + + (entry.key, entry.value) + } + + /// Remove an entry by swapping it with the last + pub(crate) fn swap_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + match self.indices.remove_entry(hash.get(), eq) { + Some(index) => { + let (key, value) = self.swap_remove_finish(index); + Some((index, key, value)) + } + None => None, + } + } + + /// Remove an entry by swapping it with the last + pub(crate) fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { + match self.entries.get(index) { + Some(entry) => { + erase_index(&mut self.indices, entry.hash, index); + Some(self.swap_remove_finish(index)) + } + None => None, + } + } + + /// Finish removing an entry by swapping it with the last + /// + /// The index should already be removed from `self.indices`. + fn swap_remove_finish(&mut self, index: usize) -> (K, V) { + // use swap_remove, but then we need to update the index that points + // to the other entry that has to move + let entry = self.entries.swap_remove(index); + + // correct index that points to the entry that had to swap places + if let Some(entry) = self.entries.get(index) { + // was not last element + // examine new element in `index` and find it in indices + let last = self.entries.len(); + update_index(&mut self.indices, entry.hash, last, index); + } + + (entry.key, entry.value) + } + + /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..` + /// + /// All of these items should still be at their original location in `entries`. + /// This is used by `drain`, which will let `Vec::drain` do the work on `entries`. + fn erase_indices(&mut self, start: usize, end: usize) { + let (init, shifted_entries) = self.entries.split_at(end); + let (start_entries, erased_entries) = init.split_at(start); + + let erased = erased_entries.len(); + let shifted = shifted_entries.len(); + let half_capacity = self.indices.buckets() / 2; + + // Use a heuristic between different strategies + if erased == 0 { + // Degenerate case, nothing to do + } else if start + shifted < half_capacity && start < erased { + // Reinsert everything, as there are few kept indices + self.indices.clear(); + + // Reinsert stable indices + for (i, entry) in enumerate(start_entries) { + self.indices.insert_no_grow(entry.hash.get(), i); + } + + // Reinsert shifted indices + for (i, entry) in (start..).zip(shifted_entries) { + self.indices.insert_no_grow(entry.hash.get(), i); + } + } else if erased + shifted < half_capacity { + // Find each affected index, as there are few to adjust + + // Find erased indices + for (i, entry) in (start..).zip(erased_entries) { + erase_index(&mut self.indices, entry.hash, i); + } + + // Find shifted indices + for ((new, old), entry) in (start..).zip(end..).zip(shifted_entries) { + update_index(&mut self.indices, entry.hash, old, new); + } + } else { + // Sweep the whole table for adjustments + self.erase_indices_sweep(start, end); + } + + debug_assert_eq!(self.indices.len(), start + shifted); + } + + pub(crate) fn retain_in_order(&mut self, mut keep: F) + where + F: FnMut(&mut K, &mut V) -> bool, + { + // Like Vec::retain in self.entries, but with mutable K and V. + // We swap-shift all the items we want to keep, truncate the rest, + // then rebuild the raw hash table with the new indexes. + let len = self.entries.len(); + let mut n_deleted = 0; + for i in 0..len { + let will_keep = { + let entry = &mut self.entries[i]; + keep(&mut entry.key, &mut entry.value) + }; + if !will_keep { + n_deleted += 1; + } else if n_deleted > 0 { + self.entries.swap(i - n_deleted, i); + } + } + if n_deleted > 0 { + self.entries.truncate(len - n_deleted); + self.rebuild_hash_table(); + } + } + + fn rebuild_hash_table(&mut self) { + self.indices.clear(); + debug_assert!(self.indices.capacity() >= self.entries.len()); + for (i, entry) in enumerate(&self.entries) { + // We should never have to reallocate, so there's no need for a real hasher. + self.indices.insert_no_grow(entry.hash.get(), i); + } + } + + pub(crate) fn reverse(&mut self) { + self.entries.reverse(); + + // No need to save hash indices, can easily calculate what they should + // be, given that this is an in-place reversal. + let len = self.entries.len(); + for i in self.indices_mut() { + *i = len - *i - 1; + } + } +} + +/// Entry for an existing key-value pair or a vacant location to +/// insert one. +pub enum Entry<'a, K, V> { + /// Existing slot with equivalent key. + Occupied(OccupiedEntry<'a, K, V>), + /// Vacant slot (no equivalent key in the map). + Vacant(VacantEntry<'a, K, V>), +} + +impl<'a, K, V> Entry<'a, K, V> { + /// Inserts the given default value in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Inserts the result of the `call` function in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert_with(self, call: F) -> &'a mut V + where + F: FnOnce() -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(call()), + } + } + + /// Inserts the result of the `call` function with a reference to the entry's key if it is + /// vacant, and returns a mutable reference to the new value. Otherwise a mutable reference to + /// an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert_with_key(self, call: F) -> &'a mut V + where + F: FnOnce(&K) -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = call(&entry.key); + entry.insert(value) + } + } + } + + /// Gets a reference to the entry's key, either within the map if occupied, + /// or else the new key that was used to find the entry. + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Return the index where the key-value pair exists or will be inserted. + pub fn index(&self) -> usize { + match *self { + Entry::Occupied(ref entry) => entry.index(), + Entry::Vacant(ref entry) => entry.index(), + } + } + + /// Modifies the entry if it is occupied. + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Entry::Occupied(mut o) => { + f(o.get_mut()); + Entry::Occupied(o) + } + x => x, + } + } + + /// Inserts a default-constructed value in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_default(self) -> &'a mut V + where + V: Default, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(V::default()), + } + } +} + +impl fmt::Debug for Entry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple(stringify!(Entry)).field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple(stringify!(Entry)).field(o).finish(), + } + } +} + +pub use self::raw::OccupiedEntry; + +// Extra methods that don't threaten the unsafe encapsulation. +impl OccupiedEntry<'_, K, V> { + /// Sets the value of the entry to `value`, and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + replace(self.get_mut(), value) + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// **NOTE:** This is equivalent to `.swap_remove()`. + pub fn remove(self) -> V { + self.swap_remove() + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(self) -> V { + self.swap_remove_entry().1 + } + + /// Remove the key, value pair stored in the map for this entry, and return the value. + /// + /// Like `Vec::remove`, the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(self) -> V { + self.shift_remove_entry().1 + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// **NOTE:** This is equivalent to `.swap_remove_entry()`. + pub fn remove_entry(self) -> (K, V) { + self.swap_remove_entry() + } +} + +impl fmt::Debug for OccupiedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!(OccupiedEntry)) + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `IndexMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +pub struct VacantEntry<'a, K, V> { + map: &'a mut IndexMapCore, + hash: HashValue, + key: K, +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + /// Gets a reference to the key that was used to find the entry. + pub fn key(&self) -> &K { + &self.key + } + + /// Takes ownership of the key, leaving the entry vacant. + pub fn into_key(self) -> K { + self.key + } + + /// Return the index where the key-value pair will be inserted. + pub fn index(&self) -> usize { + self.map.len() + } + + /// Inserts the entry's key and the given value into the map, and returns a mutable reference + /// to the value. + pub fn insert(self, value: V) -> &'a mut V { + let i = self.map.push(self.hash, self.key, value); + &mut self.map.entries[i].value + } +} + +impl fmt::Debug for VacantEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple(stringify!(VacantEntry)) + .field(self.key()) + .finish() + } +} + +#[test] +fn assert_send_sync() { + fn assert_send_sync() {} + assert_send_sync::>(); + assert_send_sync::>(); +} diff --git a/third_party/rust/indexmap/v1/crate/src/map/core/raw.rs b/third_party/rust/indexmap/v1/crate/src/map/core/raw.rs new file mode 100644 index 000000000000..168e1af3cb09 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/map/core/raw.rs @@ -0,0 +1,178 @@ +#![allow(unsafe_code)] +//! This module encapsulates the `unsafe` access to `hashbrown::raw::RawTable`, +//! mostly in dealing with its bucket "pointers". + +use super::{equivalent, Entry, HashValue, IndexMapCore, VacantEntry}; +use core::fmt; +use core::mem::replace; +use hashbrown::raw::RawTable; + +type RawBucket = hashbrown::raw::Bucket; + +pub(super) struct DebugIndices<'a>(pub &'a RawTable); +impl fmt::Debug for DebugIndices<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: we're not letting any of the buckets escape this function + let indices = unsafe { self.0.iter().map(|raw_bucket| raw_bucket.read()) }; + f.debug_list().entries(indices).finish() + } +} + +impl IndexMapCore { + /// Sweep the whole table to erase indices start..end + pub(super) fn erase_indices_sweep(&mut self, start: usize, end: usize) { + // SAFETY: we're not letting any of the buckets escape this function + unsafe { + let offset = end - start; + for bucket in self.indices.iter() { + let i = bucket.read(); + if i >= end { + bucket.write(i - offset); + } else if i >= start { + self.indices.erase(bucket); + } + } + } + } + + pub(crate) fn entry(&mut self, hash: HashValue, key: K) -> Entry<'_, K, V> + where + K: Eq, + { + let eq = equivalent(&key, &self.entries); + match self.indices.find(hash.get(), eq) { + // SAFETY: The entry is created with a live raw bucket, at the same time + // we have a &mut reference to the map, so it can not be modified further. + Some(raw_bucket) => Entry::Occupied(OccupiedEntry { + map: self, + raw_bucket, + key, + }), + None => Entry::Vacant(VacantEntry { + map: self, + hash, + key, + }), + } + } + + pub(super) fn indices_mut(&mut self) -> impl Iterator { + // SAFETY: we're not letting any of the buckets escape this function, + // only the item references that are appropriately bound to `&mut self`. + unsafe { self.indices.iter().map(|bucket| bucket.as_mut()) } + } + + /// Return the raw bucket for the given index + fn find_index(&self, index: usize) -> RawBucket { + // We'll get a "nice" bounds-check from indexing `self.entries`, + // and then we expect to find it in the table as well. + let hash = self.entries[index].hash.get(); + self.indices + .find(hash, move |&i| i == index) + .expect("index not found") + } + + pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { + // SAFETY: Can't take two `get_mut` references from one table, so we + // must use raw buckets to do the swap. This is still safe because we + // are locally sure they won't dangle, and we write them individually. + unsafe { + let raw_bucket_a = self.find_index(a); + let raw_bucket_b = self.find_index(b); + raw_bucket_a.write(b); + raw_bucket_b.write(a); + } + self.entries.swap(a, b); + } +} + +/// A view into an occupied entry in a `IndexMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +// SAFETY: The lifetime of the map reference also constrains the raw bucket, +// which is essentially a raw pointer into the map indices. +pub struct OccupiedEntry<'a, K, V> { + map: &'a mut IndexMapCore, + raw_bucket: RawBucket, + key: K, +} + +// `hashbrown::raw::Bucket` is only `Send`, not `Sync`. +// SAFETY: `&self` only accesses the bucket to read it. +unsafe impl Sync for OccupiedEntry<'_, K, V> {} + +// The parent module also adds methods that don't threaten the unsafe encapsulation. +impl<'a, K, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. + pub fn key(&self) -> &K { + &self.map.entries[self.index()].key + } + + /// Gets a reference to the entry's value in the map. + pub fn get(&self) -> &V { + &self.map.entries[self.index()].value + } + + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// `Entry` value, see `into_mut`. + pub fn get_mut(&mut self) -> &mut V { + let index = self.index(); + &mut self.map.entries[index].value + } + + /// Put the new key in the occupied entry's key slot + pub(crate) fn replace_key(self) -> K { + let index = self.index(); + let old_key = &mut self.map.entries[index].key; + replace(old_key, self.key) + } + + /// Return the index of the key-value pair + #[inline] + pub fn index(&self) -> usize { + // SAFETY: we have &mut map keep keeping the bucket stable + unsafe { self.raw_bucket.read() } + } + + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. + pub fn into_mut(self) -> &'a mut V { + let index = self.index(); + &mut self.map.entries[index].value + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like `Vec::swap_remove`, the pair is removed by swapping it with the + /// last element of the map and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_entry(self) -> (K, V) { + // SAFETY: This is safe because it can only happen once (self is consumed) + // and map.indices have not been modified since entry construction + let index = unsafe { self.map.indices.remove(self.raw_bucket) }; + self.map.swap_remove_finish(index) + } + + /// Remove and return the key, value pair stored in the map for this entry + /// + /// Like `Vec::remove`, the pair is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_entry(self) -> (K, V) { + // SAFETY: This is safe because it can only happen once (self is consumed) + // and map.indices have not been modified since entry construction + let index = unsafe { self.map.indices.remove(self.raw_bucket) }; + self.map.shift_remove_finish(index) + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/mutable_keys.rs b/third_party/rust/indexmap/v1/crate/src/mutable_keys.rs new file mode 100644 index 000000000000..35a90c4723fb --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/mutable_keys.rs @@ -0,0 +1,75 @@ +use core::hash::{BuildHasher, Hash}; + +use super::{Equivalent, IndexMap}; + +pub struct PrivateMarker {} + +/// Opt-in mutable access to keys. +/// +/// These methods expose `&mut K`, mutable references to the key as it is stored +/// in the map. +/// You are allowed to modify the keys in the hashmap **if the modification +/// does not change the key’s hash and equality**. +/// +/// If keys are modified erroneously, you can no longer look them up. +/// This is sound (memory safe) but a logical error hazard (just like +/// implementing PartialEq, Eq, or Hash incorrectly would be). +/// +/// `use` this trait to enable its methods for `IndexMap`. +pub trait MutableKeys { + type Key; + type Value; + + /// Return item index, mutable reference to key and value + fn get_full_mut2( + &mut self, + key: &Q, + ) -> Option<(usize, &mut Self::Key, &mut Self::Value)> + where + Q: Hash + Equivalent; + + /// Scan through each key-value pair in the map and keep those where the + /// closure `keep` returns `true`. + /// + /// The elements are visited in order, and remaining elements keep their + /// order. + /// + /// Computes in **O(n)** time (average). + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut Self::Key, &mut Self::Value) -> bool; + + /// This method is not useful in itself – it is there to “seal” the trait + /// for external implementation, so that we can add methods without + /// causing breaking changes. + fn __private_marker(&self) -> PrivateMarker; +} + +/// Opt-in mutable access to keys. +/// +/// See [`MutableKeys`](trait.MutableKeys.html) for more information. +impl MutableKeys for IndexMap +where + K: Eq + Hash, + S: BuildHasher, +{ + type Key = K; + type Value = V; + fn get_full_mut2(&mut self, key: &Q) -> Option<(usize, &mut K, &mut V)> + where + Q: Hash + Equivalent, + { + self.get_full_mut2_impl(key) + } + + fn retain2(&mut self, keep: F) + where + F: FnMut(&mut K, &mut V) -> bool, + { + self.retain_mut(keep) + } + + fn __private_marker(&self) -> PrivateMarker { + PrivateMarker {} + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/rayon/map.rs b/third_party/rust/indexmap/v1/crate/src/rayon/map.rs new file mode 100644 index 000000000000..8819f13ed714 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/rayon/map.rs @@ -0,0 +1,583 @@ +//! Parallel iterator types for `IndexMap` with [rayon](https://docs.rs/rayon/1.0/rayon). +//! +//! You will rarely need to interact with this module directly unless you need to name one of the +//! iterator types. +//! +//! Requires crate feature `"rayon"` + +use super::collect; +use rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; +use rayon::prelude::*; + +use crate::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::ops::RangeBounds; + +use crate::Bucket; +use crate::Entries; +use crate::IndexMap; + +/// Requires crate feature `"rayon"`. +impl IntoParallelIterator for IndexMap +where + K: Send, + V: Send, +{ + type Item = (K, V); + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +/// A parallel owning iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`into_par_iter`] method on [`IndexMap`] +/// (provided by rayon's `IntoParallelIterator` trait). See its documentation for more. +/// +/// [`into_par_iter`]: ../struct.IndexMap.html#method.into_par_iter +/// [`IndexMap`]: ../struct.IndexMap.html +pub struct IntoParIter { + entries: Vec>, +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl ParallelIterator for IntoParIter { + type Item = (K, V); + + parallel_iterator_methods!(Bucket::key_value); +} + +impl IndexedParallelIterator for IntoParIter { + indexed_parallel_iterator_methods!(Bucket::key_value); +} + +/// Requires crate feature `"rayon"`. +impl<'a, K, V, S> IntoParallelIterator for &'a IndexMap +where + K: Sync, + V: Sync, +{ + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: self.as_entries(), + } + } +} + +/// A parallel iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`par_iter`] method on [`IndexMap`] +/// (provided by rayon's `IntoParallelRefIterator` trait). See its documentation for more. +/// +/// [`par_iter`]: ../struct.IndexMap.html#method.par_iter +/// [`IndexMap`]: ../struct.IndexMap.html +pub struct ParIter<'a, K, V> { + entries: &'a [Bucket], +} + +impl Clone for ParIter<'_, K, V> { + fn clone(&self) -> Self { + ParIter { ..*self } + } +} + +impl fmt::Debug for ParIter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + parallel_iterator_methods!(Bucket::refs); +} + +impl IndexedParallelIterator for ParIter<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::refs); +} + +/// Requires crate feature `"rayon"`. +impl<'a, K, V, S> IntoParallelIterator for &'a mut IndexMap +where + K: Sync + Send, + V: Send, +{ + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + entries: self.as_entries_mut(), + } + } +} + +/// A parallel mutable iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`par_iter_mut`] method on [`IndexMap`] +/// (provided by rayon's `IntoParallelRefMutIterator` trait). See its documentation for more. +/// +/// [`par_iter_mut`]: ../struct.IndexMap.html#method.par_iter_mut +/// [`IndexMap`]: ../struct.IndexMap.html +pub struct ParIterMut<'a, K, V> { + entries: &'a mut [Bucket], +} + +impl fmt::Debug for ParIterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::refs); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync + Send, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + parallel_iterator_methods!(Bucket::ref_mut); +} + +impl IndexedParallelIterator for ParIterMut<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::ref_mut); +} + +/// Requires crate feature `"rayon"`. +impl<'a, K, V, S> ParallelDrainRange for &'a mut IndexMap +where + K: Send, + V: Send, +{ + type Item = (K, V); + type Iter = ParDrain<'a, K, V>; + + fn par_drain>(self, range: R) -> Self::Iter { + ParDrain { + entries: self.core.par_drain(range), + } + } +} + +/// A parallel draining iterator over the entries of a `IndexMap`. +/// +/// This `struct` is created by the [`par_drain`] method on [`IndexMap`] +/// (provided by rayon's `ParallelDrainRange` trait). See its documentation for more. +/// +/// [`par_drain`]: ../struct.IndexMap.html#method.par_drain +/// [`IndexMap`]: ../struct.IndexMap.html +pub struct ParDrain<'a, K: Send, V: Send> { + entries: rayon::vec::Drain<'a, Bucket>, +} + +impl ParallelIterator for ParDrain<'_, K, V> { + type Item = (K, V); + + parallel_iterator_methods!(Bucket::key_value); +} + +impl IndexedParallelIterator for ParDrain<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::key_value); +} + +/// Parallel iterator methods and other parallel methods. +/// +/// The following methods **require crate feature `"rayon"`**. +/// +/// See also the `IntoParallelIterator` implementations. +impl IndexMap +where + K: Sync, + V: Sync, +{ + /// Return a parallel iterator over the keys of the map. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the map is still preserved for operations like `reduce` and `collect`. + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + entries: self.as_entries(), + } + } + + /// Return a parallel iterator over the values of the map. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the map is still preserved for operations like `reduce` and `collect`. + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + entries: self.as_entries(), + } + } +} + +impl IndexMap +where + K: Hash + Eq + Sync, + V: Sync, + S: BuildHasher, +{ + /// Returns `true` if `self` contains all of the same key-value pairs as `other`, + /// regardless of each map's indexed order, determined in parallel. + pub fn par_eq(&self, other: &IndexMap) -> bool + where + V: PartialEq, + V2: Sync, + S2: BuildHasher + Sync, + { + self.len() == other.len() + && self + .par_iter() + .all(move |(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +/// A parallel iterator over the keys of a `IndexMap`. +/// +/// This `struct` is created by the [`par_keys`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`par_keys`]: ../struct.IndexMap.html#method.par_keys +/// [`IndexMap`]: ../struct.IndexMap.html +pub struct ParKeys<'a, K, V> { + entries: &'a [Bucket], +} + +impl Clone for ParKeys<'_, K, V> { + fn clone(&self) -> Self { + ParKeys { ..*self } + } +} + +impl fmt::Debug for ParKeys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { + type Item = &'a K; + + parallel_iterator_methods!(Bucket::key_ref); +} + +impl IndexedParallelIterator for ParKeys<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::key_ref); +} + +/// A parallel iterator over the values of a `IndexMap`. +/// +/// This `struct` is created by the [`par_values`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`par_values`]: ../struct.IndexMap.html#method.par_values +/// [`IndexMap`]: ../struct.IndexMap.html +pub struct ParValues<'a, K, V> { + entries: &'a [Bucket], +} + +impl Clone for ParValues<'_, K, V> { + fn clone(&self) -> Self { + ParValues { ..*self } + } +} + +impl fmt::Debug for ParValues<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { + type Item = &'a V; + + parallel_iterator_methods!(Bucket::value_ref); +} + +impl IndexedParallelIterator for ParValues<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::value_ref); +} + +/// Requires crate feature `"rayon"`. +impl IndexMap +where + K: Send, + V: Send, +{ + /// Return a parallel iterator over mutable references to the values of the map + /// + /// While parallel iterators can process items in any order, their relative order + /// in the map is still preserved for operations like `reduce` and `collect`. + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + entries: self.as_entries_mut(), + } + } +} + +impl IndexMap +where + K: Hash + Eq + Send, + V: Send, + S: BuildHasher, +{ + /// Sort the map’s key-value pairs in parallel, by the default ordering of the keys. + pub fn par_sort_keys(&mut self) + where + K: Ord, + { + self.with_entries(|entries| { + entries.par_sort_by(|a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map’s key-value pairs in place and in parallel, using the comparison + /// function `cmp`. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + pub fn par_sort_by(&mut self, cmp: F) + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map in parallel and return a by-value parallel + /// iterator of the key-value pairs with the result. + pub fn par_sorted_by(self, cmp: F) -> IntoParIter + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoParIter { entries } + } + + /// Sort the map's key-value pairs in parallel, by the default ordering of the keys. + pub fn par_sort_unstable_keys(&mut self) + where + K: Ord, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(|a, b| K::cmp(&a.key, &b.key)); + }); + } + + /// Sort the map's key-value pairs in place and in parallel, using the comparison + /// function `cmp`. + /// + /// The comparison function receives two key and value pairs to compare (you + /// can sort by keys or values or their combination as needed). + pub fn par_sort_unstable_by(&mut self, cmp: F) + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + }); + } + + /// Sort the key-value pairs of the map in parallel and return a by-value parallel + /// iterator of the key-value pairs with the result. + pub fn par_sorted_unstable_by(self, cmp: F) -> IntoParIter + where + F: Fn(&K, &V, &K, &V) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &a.value, &b.key, &b.value)); + IntoParIter { entries } + } +} + +/// A parallel mutable iterator over the values of a `IndexMap`. +/// +/// This `struct` is created by the [`par_values_mut`] method on [`IndexMap`]. See its +/// documentation for more. +/// +/// [`par_values_mut`]: ../struct.IndexMap.html#method.par_values_mut +/// [`IndexMap`]: ../struct.IndexMap.html +pub struct ParValuesMut<'a, K, V> { + entries: &'a mut [Bucket], +} + +impl fmt::Debug for ParValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::value_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, K: Send, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { + type Item = &'a mut V; + + parallel_iterator_methods!(Bucket::value_mut); +} + +impl IndexedParallelIterator for ParValuesMut<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::value_mut); +} + +/// Requires crate feature `"rayon"`. +impl FromParallelIterator<(K, V)> for IndexMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Default + Send, +{ + fn from_par_iter(iter: I) -> Self + where + I: IntoParallelIterator, + { + let list = collect(iter); + let len = list.iter().map(Vec::len).sum(); + let mut map = Self::with_capacity_and_hasher(len, S::default()); + for vec in list { + map.extend(vec); + } + map + } +} + +/// Requires crate feature `"rayon"`. +impl ParallelExtend<(K, V)> for IndexMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +/// Requires crate feature `"rayon"`. +impl<'a, K: 'a, V: 'a, S> ParallelExtend<(&'a K, &'a V)> for IndexMap +where + K: Copy + Eq + Hash + Send + Sync, + V: Copy + Send + Sync, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::string::String; + + #[test] + fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut map = IndexMap::new(); + + for &elt in &insert { + map.insert(elt, ()); + } + + assert_eq!(map.par_keys().count(), map.len()); + assert_eq!(map.par_keys().count(), insert.len()); + insert.par_iter().zip(map.par_keys()).for_each(|(a, b)| { + assert_eq!(a, b); + }); + (0..insert.len()) + .into_par_iter() + .zip(map.par_keys()) + .for_each(|(i, k)| { + assert_eq!(map.get_index(i).unwrap().0, k); + }); + } + + #[test] + fn partial_eq_and_eq() { + let mut map_a = IndexMap::new(); + map_a.insert(1, "1"); + map_a.insert(2, "2"); + let mut map_b = map_a.clone(); + assert!(map_a.par_eq(&map_b)); + map_b.swap_remove(&1); + assert!(!map_a.par_eq(&map_b)); + map_b.insert(3, "3"); + assert!(!map_a.par_eq(&map_b)); + + let map_c: IndexMap<_, String> = + map_b.into_par_iter().map(|(k, v)| (k, v.into())).collect(); + assert!(!map_a.par_eq(&map_c)); + assert!(!map_c.par_eq(&map_a)); + } + + #[test] + fn extend() { + let mut map = IndexMap::new(); + map.par_extend(vec![(&1, &2), (&3, &4)]); + map.par_extend(vec![(5, 6)]); + assert_eq!( + map.into_par_iter().collect::>(), + vec![(1, 2), (3, 4), (5, 6)] + ); + } + + #[test] + fn keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_par_iter().collect(); + let keys: Vec<_> = map.par_keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: IndexMap<_, _> = vec.into_par_iter().collect(); + let values: Vec<_> = map.par_values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: IndexMap<_, _> = vec.into_par_iter().collect(); + map.par_values_mut().for_each(|value| *value *= 2); + let values: Vec<_> = map.par_values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/rayon/mod.rs b/third_party/rust/indexmap/v1/crate/src/rayon/mod.rs new file mode 100644 index 000000000000..ebb1ac2d1e0d --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/rayon/mod.rs @@ -0,0 +1,27 @@ +use rayon::prelude::*; + +use alloc::collections::LinkedList; + +use crate::vec::Vec; + +pub mod map; +pub mod set; + +// This form of intermediate collection is also how Rayon collects `HashMap`. +// Note that the order will also be preserved! +fn collect(iter: I) -> LinkedList> { + iter.into_par_iter() + .fold(Vec::new, |mut vec, elem| { + vec.push(elem); + vec + }) + .map(|vec| { + let mut list = LinkedList::new(); + list.push_back(vec); + list + }) + .reduce(LinkedList::new, |mut list1, mut list2| { + list1.append(&mut list2); + list1 + }) +} diff --git a/third_party/rust/indexmap/v1/crate/src/rayon/set.rs b/third_party/rust/indexmap/v1/crate/src/rayon/set.rs new file mode 100644 index 000000000000..5a4ac97d11b7 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/rayon/set.rs @@ -0,0 +1,741 @@ +//! Parallel iterator types for `IndexSet` with [rayon](https://docs.rs/rayon/1.0/rayon). +//! +//! You will rarely need to interact with this module directly unless you need to name one of the +//! iterator types. +//! +//! Requires crate feature `"rayon"`. + +use super::collect; +use rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; +use rayon::prelude::*; + +use crate::vec::Vec; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::ops::RangeBounds; + +use crate::Entries; +use crate::IndexSet; + +type Bucket = crate::Bucket; + +/// Requires crate feature `"rayon"`. +impl IntoParallelIterator for IndexSet +where + T: Send, +{ + type Item = T; + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } +} + +/// A parallel owning iterator over the items of a `IndexSet`. +/// +/// This `struct` is created by the [`into_par_iter`] method on [`IndexSet`] +/// (provided by rayon's `IntoParallelIterator` trait). See its documentation for more. +/// +/// [`IndexSet`]: ../struct.IndexSet.html +/// [`into_par_iter`]: ../struct.IndexSet.html#method.into_par_iter +pub struct IntoParIter { + entries: Vec>, +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + parallel_iterator_methods!(Bucket::key); +} + +impl IndexedParallelIterator for IntoParIter { + indexed_parallel_iterator_methods!(Bucket::key); +} + +/// Requires crate feature `"rayon"`. +impl<'a, T, S> IntoParallelIterator for &'a IndexSet +where + T: Sync, +{ + type Item = &'a T; + type Iter = ParIter<'a, T>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: self.as_entries(), + } + } +} + +/// A parallel iterator over the items of a `IndexSet`. +/// +/// This `struct` is created by the [`par_iter`] method on [`IndexSet`] +/// (provided by rayon's `IntoParallelRefIterator` trait). See its documentation for more. +/// +/// [`IndexSet`]: ../struct.IndexSet.html +/// [`par_iter`]: ../struct.IndexSet.html#method.par_iter +pub struct ParIter<'a, T> { + entries: &'a [Bucket], +} + +impl Clone for ParIter<'_, T> { + fn clone(&self) -> Self { + ParIter { ..*self } + } +} + +impl fmt::Debug for ParIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.entries.iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + parallel_iterator_methods!(Bucket::key_ref); +} + +impl IndexedParallelIterator for ParIter<'_, T> { + indexed_parallel_iterator_methods!(Bucket::key_ref); +} + +/// Requires crate feature `"rayon"`. +impl<'a, T, S> ParallelDrainRange for &'a mut IndexSet +where + T: Send, +{ + type Item = T; + type Iter = ParDrain<'a, T>; + + fn par_drain>(self, range: R) -> Self::Iter { + ParDrain { + entries: self.map.core.par_drain(range), + } + } +} + +/// A parallel draining iterator over the items of a `IndexSet`. +/// +/// This `struct` is created by the [`par_drain`] method on [`IndexSet`] +/// (provided by rayon's `ParallelDrainRange` trait). See its documentation for more. +/// +/// [`par_drain`]: ../struct.IndexSet.html#method.par_drain +/// [`IndexSet`]: ../struct.IndexSet.html +pub struct ParDrain<'a, T: Send> { + entries: rayon::vec::Drain<'a, Bucket>, +} + +impl ParallelIterator for ParDrain<'_, T> { + type Item = T; + + parallel_iterator_methods!(Bucket::key); +} + +impl IndexedParallelIterator for ParDrain<'_, T> { + indexed_parallel_iterator_methods!(Bucket::key); +} + +/// Parallel iterator methods and other parallel methods. +/// +/// The following methods **require crate feature `"rayon"`**. +/// +/// See also the `IntoParallelIterator` implementations. +impl IndexSet +where + T: Hash + Eq + Sync, + S: BuildHasher + Sync, +{ + /// Return a parallel iterator over the values that are in `self` but not `other`. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the `self` set is still preserved for operations like `reduce` and `collect`. + pub fn par_difference<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> ParDifference<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParDifference { + set1: self, + set2: other, + } + } + + /// Return a parallel iterator over the values that are in `self` or `other`, + /// but not in both. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the sets is still preserved for operations like `reduce` and `collect`. + /// Values from `self` are produced in their original order, followed by + /// values from `other` in their original order. + pub fn par_symmetric_difference<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> ParSymmetricDifference<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParSymmetricDifference { + set1: self, + set2: other, + } + } + + /// Return a parallel iterator over the values that are in both `self` and `other`. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the `self` set is still preserved for operations like `reduce` and `collect`. + pub fn par_intersection<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> ParIntersection<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParIntersection { + set1: self, + set2: other, + } + } + + /// Return a parallel iterator over all values that are in `self` or `other`. + /// + /// While parallel iterators can process items in any order, their relative order + /// in the sets is still preserved for operations like `reduce` and `collect`. + /// Values from `self` are produced in their original order, followed by + /// values that are unique to `other` in their original order. + pub fn par_union<'a, S2>(&'a self, other: &'a IndexSet) -> ParUnion<'a, T, S, S2> + where + S2: BuildHasher + Sync, + { + ParUnion { + set1: self, + set2: other, + } + } + + /// Returns `true` if `self` contains all of the same values as `other`, + /// regardless of each set's indexed order, determined in parallel. + pub fn par_eq(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + self.len() == other.len() && self.par_is_subset(other) + } + + /// Returns `true` if `self` has no elements in common with `other`, + /// determined in parallel. + pub fn par_is_disjoint(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + if self.len() <= other.len() { + self.par_iter().all(move |value| !other.contains(value)) + } else { + other.par_iter().all(move |value| !self.contains(value)) + } + } + + /// Returns `true` if all elements of `other` are contained in `self`, + /// determined in parallel. + pub fn par_is_superset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + other.par_is_subset(self) + } + + /// Returns `true` if all elements of `self` are contained in `other`, + /// determined in parallel. + pub fn par_is_subset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher + Sync, + { + self.len() <= other.len() && self.par_iter().all(move |value| other.contains(value)) + } +} + +/// A parallel iterator producing elements in the difference of `IndexSet`s. +/// +/// This `struct` is created by the [`par_difference`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: ../struct.IndexSet.html +/// [`par_difference`]: ../struct.IndexSet.html#method.par_difference +pub struct ParDifference<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParDifference<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParDifference { ..*self } + } +} + +impl fmt::Debug for ParDifference<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.set1.difference(&self.set2)) + .finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParDifference<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_iter() + .filter(move |&item| !set2.contains(item)) + .drive_unindexed(consumer) + } +} + +/// A parallel iterator producing elements in the intersection of `IndexSet`s. +/// +/// This `struct` is created by the [`par_intersection`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: ../struct.IndexSet.html +/// [`par_intersection`]: ../struct.IndexSet.html#method.par_intersection +pub struct ParIntersection<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParIntersection<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParIntersection { ..*self } + } +} + +impl fmt::Debug for ParIntersection<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.set1.intersection(&self.set2)) + .finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParIntersection<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_iter() + .filter(move |&item| set2.contains(item)) + .drive_unindexed(consumer) + } +} + +/// A parallel iterator producing elements in the symmetric difference of `IndexSet`s. +/// +/// This `struct` is created by the [`par_symmetric_difference`] method on +/// [`IndexSet`]. See its documentation for more. +/// +/// [`IndexSet`]: ../struct.IndexSet.html +/// [`par_symmetric_difference`]: ../struct.IndexSet.html#method.par_symmetric_difference +pub struct ParSymmetricDifference<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParSymmetricDifference<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParSymmetricDifference { ..*self } + } +} + +impl fmt::Debug for ParSymmetricDifference<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.set1.symmetric_difference(&self.set2)) + .finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParSymmetricDifference<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_difference(set2) + .chain(set2.par_difference(set1)) + .drive_unindexed(consumer) + } +} + +/// A parallel iterator producing elements in the union of `IndexSet`s. +/// +/// This `struct` is created by the [`par_union`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: ../struct.IndexSet.html +/// [`par_union`]: ../struct.IndexSet.html#method.par_union +pub struct ParUnion<'a, T, S1, S2> { + set1: &'a IndexSet, + set2: &'a IndexSet, +} + +impl Clone for ParUnion<'_, T, S1, S2> { + fn clone(&self) -> Self { + ParUnion { ..*self } + } +} + +impl fmt::Debug for ParUnion<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.set1.union(&self.set2)).finish() + } +} + +impl<'a, T, S1, S2> ParallelIterator for ParUnion<'a, T, S1, S2> +where + T: Hash + Eq + Sync, + S1: BuildHasher + Sync, + S2: BuildHasher + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let Self { set1, set2 } = self; + + set1.par_iter() + .chain(set2.par_difference(set1)) + .drive_unindexed(consumer) + } +} + +/// Parallel sorting methods. +/// +/// The following methods **require crate feature `"rayon"`**. +impl IndexSet +where + T: Hash + Eq + Send, + S: BuildHasher + Send, +{ + /// Sort the set’s values in parallel by their default ordering. + pub fn par_sort(&mut self) + where + T: Ord, + { + self.with_entries(|entries| { + entries.par_sort_by(|a, b| T::cmp(&a.key, &b.key)); + }); + } + + /// Sort the set’s values in place and in parallel, using the comparison function `cmp`. + pub fn par_sort_by(&mut self, cmp: F) + where + F: Fn(&T, &T) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_by(move |a, b| cmp(&a.key, &b.key)); + }); + } + + /// Sort the values of the set in parallel and return a by-value parallel iterator of + /// the values with the result. + pub fn par_sorted_by(self, cmp: F) -> IntoParIter + where + F: Fn(&T, &T) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_by(move |a, b| cmp(&a.key, &b.key)); + IntoParIter { entries } + } + + /// Sort the set's values in parallel by their default ordering. + pub fn par_sort_unstable(&mut self) + where + T: Ord, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(|a, b| T::cmp(&a.key, &b.key)); + }); + } + + /// Sort the set’s values in place and in parallel, using the comparison function `cmp`. + pub fn par_sort_unstable_by(&mut self, cmp: F) + where + F: Fn(&T, &T) -> Ordering + Sync, + { + self.with_entries(|entries| { + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &b.key)); + }); + } + + /// Sort the values of the set in parallel and return a by-value parallel iterator of + /// the values with the result. + pub fn par_sorted_unstable_by(self, cmp: F) -> IntoParIter + where + F: Fn(&T, &T) -> Ordering + Sync, + { + let mut entries = self.into_entries(); + entries.par_sort_unstable_by(move |a, b| cmp(&a.key, &b.key)); + IntoParIter { entries } + } +} + +/// Requires crate feature `"rayon"`. +impl FromParallelIterator for IndexSet +where + T: Eq + Hash + Send, + S: BuildHasher + Default + Send, +{ + fn from_par_iter(iter: I) -> Self + where + I: IntoParallelIterator, + { + let list = collect(iter); + let len = list.iter().map(Vec::len).sum(); + let mut set = Self::with_capacity_and_hasher(len, S::default()); + for vec in list { + set.extend(vec); + } + set + } +} + +/// Requires crate feature `"rayon"`. +impl ParallelExtend for IndexSet +where + T: Eq + Hash + Send, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +/// Requires crate feature `"rayon"`. +impl<'a, T: 'a, S> ParallelExtend<&'a T> for IndexSet +where + T: Copy + Eq + Hash + Send + Sync, + S: BuildHasher + Send, +{ + fn par_extend(&mut self, iter: I) + where + I: IntoParallelIterator, + { + for vec in collect(iter) { + self.extend(vec); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.par_iter().count(), set.len()); + assert_eq!(set.par_iter().count(), insert.len()); + insert.par_iter().zip(&set).for_each(|(a, b)| { + assert_eq!(a, b); + }); + (0..insert.len()) + .into_par_iter() + .zip(&set) + .for_each(|(i, v)| { + assert_eq!(set.get_index(i).unwrap(), v); + }); + } + + #[test] + fn partial_eq_and_eq() { + let mut set_a = IndexSet::new(); + set_a.insert(1); + set_a.insert(2); + let mut set_b = set_a.clone(); + assert!(set_a.par_eq(&set_b)); + set_b.swap_remove(&1); + assert!(!set_a.par_eq(&set_b)); + set_b.insert(3); + assert!(!set_a.par_eq(&set_b)); + + let set_c: IndexSet<_> = set_b.into_par_iter().collect(); + assert!(!set_a.par_eq(&set_c)); + assert!(!set_c.par_eq(&set_a)); + } + + #[test] + fn extend() { + let mut set = IndexSet::new(); + set.par_extend(vec![&1, &2, &3, &4]); + set.par_extend(vec![5, 6]); + assert_eq!( + set.into_par_iter().collect::>(), + vec![1, 2, 3, 4, 5, 6] + ); + } + + #[test] + fn comparisons() { + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).collect(); + + assert!(!set_a.par_is_disjoint(&set_a)); + assert!(set_a.par_is_subset(&set_a)); + assert!(set_a.par_is_superset(&set_a)); + + assert!(set_a.par_is_disjoint(&set_b)); + assert!(set_b.par_is_disjoint(&set_a)); + assert!(!set_a.par_is_subset(&set_b)); + assert!(!set_b.par_is_subset(&set_a)); + assert!(!set_a.par_is_superset(&set_b)); + assert!(!set_b.par_is_superset(&set_a)); + + assert!(!set_a.par_is_disjoint(&set_c)); + assert!(!set_c.par_is_disjoint(&set_a)); + assert!(set_a.par_is_subset(&set_c)); + assert!(!set_c.par_is_subset(&set_a)); + assert!(!set_a.par_is_superset(&set_c)); + assert!(set_c.par_is_superset(&set_a)); + + assert!(!set_c.par_is_disjoint(&set_d)); + assert!(!set_d.par_is_disjoint(&set_c)); + assert!(!set_c.par_is_subset(&set_d)); + assert!(!set_d.par_is_subset(&set_c)); + assert!(!set_c.par_is_superset(&set_d)); + assert!(!set_d.par_is_superset(&set_c)); + } + + #[test] + fn iter_comparisons() { + use std::iter::empty; + + fn check<'a, I1, I2>(iter1: I1, iter2: I2) + where + I1: ParallelIterator, + I2: Iterator, + { + let v1: Vec<_> = iter1.copied().collect(); + let v2: Vec<_> = iter2.collect(); + assert_eq!(v1, v2); + } + + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + check(set_a.par_difference(&set_a), empty()); + check(set_a.par_symmetric_difference(&set_a), empty()); + check(set_a.par_intersection(&set_a), 0..3); + check(set_a.par_union(&set_a), 0..3); + + check(set_a.par_difference(&set_b), 0..3); + check(set_b.par_difference(&set_a), 3..6); + check(set_a.par_symmetric_difference(&set_b), 0..6); + check(set_b.par_symmetric_difference(&set_a), (3..6).chain(0..3)); + check(set_a.par_intersection(&set_b), empty()); + check(set_b.par_intersection(&set_a), empty()); + check(set_a.par_union(&set_b), 0..6); + check(set_b.par_union(&set_a), (3..6).chain(0..3)); + + check(set_a.par_difference(&set_c), empty()); + check(set_c.par_difference(&set_a), 3..6); + check(set_a.par_symmetric_difference(&set_c), 3..6); + check(set_c.par_symmetric_difference(&set_a), 3..6); + check(set_a.par_intersection(&set_c), 0..3); + check(set_c.par_intersection(&set_a), 0..3); + check(set_a.par_union(&set_c), 0..6); + check(set_c.par_union(&set_a), 0..6); + + check(set_c.par_difference(&set_d), 0..3); + check(set_d.par_difference(&set_c), (6..9).rev()); + check( + set_c.par_symmetric_difference(&set_d), + (0..3).chain((6..9).rev()), + ); + check( + set_d.par_symmetric_difference(&set_c), + (6..9).rev().chain(0..3), + ); + check(set_c.par_intersection(&set_d), 3..6); + check(set_d.par_intersection(&set_c), (3..6).rev()); + check(set_c.par_union(&set_d), (0..6).chain((6..9).rev())); + check(set_d.par_union(&set_c), (3..9).rev().chain(0..3)); + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/rustc.rs b/third_party/rust/indexmap/v1/crate/src/rustc.rs new file mode 100644 index 000000000000..b843858b325d --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/rustc.rs @@ -0,0 +1,158 @@ +//! Minimal support for `rustc-rayon`, not intended for general use. + +use crate::vec::Vec; +use crate::{Bucket, Entries, IndexMap, IndexSet}; + +use rustc_rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; +use rustc_rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; + +mod map { + use super::*; + + impl IntoParallelIterator for IndexMap + where + K: Send, + V: Send, + { + type Item = (K, V); + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } + } + + pub struct IntoParIter { + entries: Vec>, + } + + impl ParallelIterator for IntoParIter { + type Item = (K, V); + + parallel_iterator_methods!(Bucket::key_value); + } + + impl IndexedParallelIterator for IntoParIter { + indexed_parallel_iterator_methods!(Bucket::key_value); + } + + impl<'a, K, V, S> IntoParallelIterator for &'a IndexMap + where + K: Sync, + V: Sync, + { + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: self.as_entries(), + } + } + } + + pub struct ParIter<'a, K, V> { + entries: &'a [Bucket], + } + + impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + parallel_iterator_methods!(Bucket::refs); + } + + impl IndexedParallelIterator for ParIter<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::refs); + } + + impl<'a, K, V, S> IntoParallelIterator for &'a mut IndexMap + where + K: Sync + Send, + V: Send, + { + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + entries: self.as_entries_mut(), + } + } + } + + pub struct ParIterMut<'a, K, V> { + entries: &'a mut [Bucket], + } + + impl<'a, K: Sync + Send, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + parallel_iterator_methods!(Bucket::ref_mut); + } + + impl IndexedParallelIterator for ParIterMut<'_, K, V> { + indexed_parallel_iterator_methods!(Bucket::ref_mut); + } +} + +mod set { + use super::*; + + impl IntoParallelIterator for IndexSet + where + T: Send, + { + type Item = T; + type Iter = IntoParIter; + + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + entries: self.into_entries(), + } + } + } + + pub struct IntoParIter { + entries: Vec>, + } + + impl ParallelIterator for IntoParIter { + type Item = T; + + parallel_iterator_methods!(Bucket::key); + } + + impl IndexedParallelIterator for IntoParIter { + indexed_parallel_iterator_methods!(Bucket::key); + } + + impl<'a, T, S> IntoParallelIterator for &'a IndexSet + where + T: Sync, + { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + fn into_par_iter(self) -> Self::Iter { + ParIter { + entries: self.as_entries(), + } + } + } + + pub struct ParIter<'a, T> { + entries: &'a [Bucket], + } + + impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + parallel_iterator_methods!(Bucket::key_ref); + } + + impl IndexedParallelIterator for ParIter<'_, T> { + indexed_parallel_iterator_methods!(Bucket::key_ref); + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/serde.rs b/third_party/rust/indexmap/v1/crate/src/serde.rs new file mode 100644 index 000000000000..c6dd6d5ea0fc --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/serde.rs @@ -0,0 +1,155 @@ +use serde::de::value::{MapDeserializer, SeqDeserializer}; +use serde::de::{ + Deserialize, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor, +}; +use serde::ser::{Serialize, Serializer}; + +use core::fmt::{self, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; + +use crate::IndexMap; + +/// Requires crate feature `"serde"` or `"serde-1"` +impl Serialize for IndexMap +where + K: Serialize + Hash + Eq, + V: Serialize, + S: BuildHasher, +{ + fn serialize(&self, serializer: T) -> Result + where + T: Serializer, + { + serializer.collect_map(self) + } +} + +struct IndexMapVisitor(PhantomData<(K, V, S)>); + +impl<'de, K, V, S> Visitor<'de> for IndexMapVisitor +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + type Value = IndexMap; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a map") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut values = + IndexMap::with_capacity_and_hasher(map.size_hint().unwrap_or(0), S::default()); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } +} + +/// Requires crate feature `"serde"` or `"serde-1"` +impl<'de, K, V, S> Deserialize<'de> for IndexMap +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(IndexMapVisitor(PhantomData)) + } +} + +impl<'de, K, V, S, E> IntoDeserializer<'de, E> for IndexMap +where + K: IntoDeserializer<'de, E> + Eq + Hash, + V: IntoDeserializer<'de, E>, + S: BuildHasher, + E: Error, +{ + type Deserializer = MapDeserializer<'de, ::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +use crate::IndexSet; + +/// Requires crate feature `"serde"` or `"serde-1"` +impl Serialize for IndexSet +where + T: Serialize + Hash + Eq, + S: BuildHasher, +{ + fn serialize(&self, serializer: Se) -> Result + where + Se: Serializer, + { + serializer.collect_seq(self) + } +} + +struct IndexSetVisitor(PhantomData<(T, S)>); + +impl<'de, T, S> Visitor<'de> for IndexSetVisitor +where + T: Deserialize<'de> + Eq + Hash, + S: Default + BuildHasher, +{ + type Value = IndexSet; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a set") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut values = + IndexSet::with_capacity_and_hasher(seq.size_hint().unwrap_or(0), S::default()); + + while let Some(value) = seq.next_element()? { + values.insert(value); + } + + Ok(values) + } +} + +/// Requires crate feature `"serde"` or `"serde-1"` +impl<'de, T, S> Deserialize<'de> for IndexSet +where + T: Deserialize<'de> + Eq + Hash, + S: Default + BuildHasher, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(IndexSetVisitor(PhantomData)) + } +} + +impl<'de, T, S, E> IntoDeserializer<'de, E> for IndexSet +where + T: IntoDeserializer<'de, E> + Eq + Hash, + S: BuildHasher, + E: Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/serde_seq.rs b/third_party/rust/indexmap/v1/crate/src/serde_seq.rs new file mode 100644 index 000000000000..d326a02e377a --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/serde_seq.rs @@ -0,0 +1,112 @@ +//! Functions to serialize and deserialize an `IndexMap` as an ordered sequence. +//! +//! The default `serde` implementation serializes `IndexMap` as a normal map, +//! but there is no guarantee that serialization formats will preserve the order +//! of the key-value pairs. This module serializes `IndexMap` as a sequence of +//! `(key, value)` elements instead, in order. +//! +//! This module may be used in a field attribute for derived implementations: +//! +//! ``` +//! # use indexmap::IndexMap; +//! # use serde_derive::{Deserialize, Serialize}; +//! #[derive(Deserialize, Serialize)] +//! struct Data { +//! #[serde(with = "indexmap::serde_seq")] +//! map: IndexMap, +//! // ... +//! } +//! ``` +//! +//! Requires crate feature `"serde"` or `"serde-1"` + +use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; +use serde::ser::{Serialize, Serializer}; + +use core::fmt::{self, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; + +use crate::IndexMap; + +/// Serializes an `IndexMap` as an ordered sequence. +/// +/// This function may be used in a field attribute for deriving `Serialize`: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde_derive::Serialize; +/// #[derive(Serialize)] +/// struct Data { +/// #[serde(serialize_with = "indexmap::serde_seq::serialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +/// +/// Requires crate feature `"serde"` or `"serde-1"` +pub fn serialize(map: &IndexMap, serializer: T) -> Result +where + K: Serialize + Hash + Eq, + V: Serialize, + S: BuildHasher, + T: Serializer, +{ + serializer.collect_seq(map) +} + +/// Visitor to deserialize a *sequenced* `IndexMap` +struct SeqVisitor(PhantomData<(K, V, S)>); + +impl<'de, K, V, S> Visitor<'de> for SeqVisitor +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + type Value = IndexMap; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a sequenced map") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = seq.size_hint().unwrap_or(0); + let mut map = IndexMap::with_capacity_and_hasher(capacity, S::default()); + + while let Some((key, value)) = seq.next_element()? { + map.insert(key, value); + } + + Ok(map) + } +} + +/// Deserializes an `IndexMap` from an ordered sequence. +/// +/// This function may be used in a field attribute for deriving `Deserialize`: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde_derive::Deserialize; +/// #[derive(Deserialize)] +/// struct Data { +/// #[serde(deserialize_with = "indexmap::serde_seq::deserialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +/// +/// Requires crate feature `"serde"` or `"serde-1"` +pub fn deserialize<'de, D, K, V, S>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + deserializer.deserialize_seq(SeqVisitor(PhantomData)) +} diff --git a/third_party/rust/indexmap/v1/crate/src/set.rs b/third_party/rust/indexmap/v1/crate/src/set.rs new file mode 100644 index 000000000000..e82a8d07d708 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/set.rs @@ -0,0 +1,1892 @@ +//! A hash set implemented using `IndexMap` + +#[cfg(feature = "rayon")] +pub use crate::rayon::set as rayon; + +#[cfg(has_std)] +use std::collections::hash_map::RandomState; + +use crate::vec::{self, Vec}; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FromIterator, FusedIterator}; +use core::ops::{BitAnd, BitOr, BitXor, Index, RangeBounds, Sub}; +use core::slice; + +use super::{Entries, Equivalent, IndexMap}; + +type Bucket = super::Bucket; + +/// A hash set where the iteration order of the values is independent of their +/// hash values. +/// +/// The interface is closely compatible with the standard `HashSet`, but also +/// has additional features. +/// +/// # Order +/// +/// The values have a consistent order that is determined by the sequence of +/// insertion and removal calls on the set. The order does not depend on the +/// values or the hash function at all. Note that insertion order and value +/// are not affected if a re-insertion is attempted once an element is +/// already present. +/// +/// All iterators traverse the set *in order*. Set operation iterators like +/// `union` produce a concatenated order, as do their matching "bitwise" +/// operators. See their documentation for specifics. +/// +/// The insertion order is preserved, with **notable exceptions** like the +/// `.remove()` or `.swap_remove()` methods. Methods such as `.sort_by()` of +/// course result in a new order, depending on the sorting order. +/// +/// # Indices +/// +/// The values are indexed in a compact range without holes in the range +/// `0..self.len()`. For example, the method `.get_full` looks up the index for +/// a value, and the method `.get_index` looks up the value by index. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexSet; +/// +/// // Collects which letters appear in a sentence. +/// let letters: IndexSet<_> = "a short treatise on fungi".chars().collect(); +/// +/// assert!(letters.contains(&'s')); +/// assert!(letters.contains(&'t')); +/// assert!(letters.contains(&'u')); +/// assert!(!letters.contains(&'y')); +/// ``` +#[cfg(has_std)] +pub struct IndexSet { + pub(crate) map: IndexMap, +} +#[cfg(not(has_std))] +pub struct IndexSet { + pub(crate) map: IndexMap, +} + +impl Clone for IndexSet +where + T: Clone, + S: Clone, +{ + fn clone(&self) -> Self { + IndexSet { + map: self.map.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.map.clone_from(&other.map); + } +} + +impl Entries for IndexSet { + type Entry = Bucket; + + #[inline] + fn into_entries(self) -> Vec { + self.map.into_entries() + } + + #[inline] + fn as_entries(&self) -> &[Self::Entry] { + self.map.as_entries() + } + + #[inline] + fn as_entries_mut(&mut self) -> &mut [Self::Entry] { + self.map.as_entries_mut() + } + + fn with_entries(&mut self, f: F) + where + F: FnOnce(&mut [Self::Entry]), + { + self.map.with_entries(f); + } +} + +impl fmt::Debug for IndexSet +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if cfg!(not(feature = "test_debug")) { + f.debug_set().entries(self.iter()).finish() + } else { + // Let the inner `IndexMap` print all of its details + f.debug_struct("IndexSet").field("map", &self.map).finish() + } + } +} + +#[cfg(has_std)] +impl IndexSet { + /// Create a new set. (Does not allocate.) + pub fn new() -> Self { + IndexSet { + map: IndexMap::new(), + } + } + + /// Create a new set with capacity for `n` elements. + /// (Does not allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + pub fn with_capacity(n: usize) -> Self { + IndexSet { + map: IndexMap::with_capacity(n), + } + } +} + +impl IndexSet { + /// Create a new set with capacity for `n` elements. + /// (Does not allocate if `n` is zero.) + /// + /// Computes in **O(n)** time. + pub fn with_capacity_and_hasher(n: usize, hash_builder: S) -> Self { + IndexSet { + map: IndexMap::with_capacity_and_hasher(n, hash_builder), + } + } + + /// Create a new set with `hash_builder`. + /// + /// This function is `const`, so it + /// can be called in `static` contexts. + pub const fn with_hasher(hash_builder: S) -> Self { + IndexSet { + map: IndexMap::with_hasher(hash_builder), + } + } + + /// Computes in **O(1)** time. + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// Return a reference to the set's `BuildHasher`. + pub fn hasher(&self) -> &S { + self.map.hasher() + } + + /// Return the number of elements in the set. + /// + /// Computes in **O(1)** time. + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns true if the set contains no elements. + /// + /// Computes in **O(1)** time. + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Return an iterator over the values of the set, in their order + pub fn iter(&self) -> Iter<'_, T> { + Iter { + iter: self.map.keys().iter, + } + } + + /// Remove all elements in the set, while preserving its capacity. + /// + /// Computes in **O(n)** time. + pub fn clear(&mut self) { + self.map.clear(); + } + + /// Shortens the set, keeping the first `len` elements and dropping the rest. + /// + /// If `len` is greater than the set's current length, this has no effect. + pub fn truncate(&mut self, len: usize) { + self.map.truncate(len); + } + + /// Clears the `IndexSet` in the given index range, returning those values + /// as a drain iterator. + /// + /// The range may be any type that implements `RangeBounds`, + /// including all of the `std::ops::Range*` types, or even a tuple pair of + /// `Bound` start and end values. To drain the set entirely, use `RangeFull` + /// like `set.drain(..)`. + /// + /// This shifts down all entries following the drained range to fill the + /// gap, and keeps the allocated memory for reuse. + /// + /// ***Panics*** if the starting point is greater than the end point or if + /// the end point is greater than the length of the set. + pub fn drain(&mut self, range: R) -> Drain<'_, T> + where + R: RangeBounds, + { + Drain { + iter: self.map.drain(range).iter, + } + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated set containing the elements in the range + /// `[at, len)`. After the call, the original set will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// ***Panics*** if `at > len`. + pub fn split_off(&mut self, at: usize) -> Self + where + S: Clone, + { + Self { + map: self.map.split_off(at), + } + } +} + +impl IndexSet +where + T: Hash + Eq, + S: BuildHasher, +{ + /// Reserve capacity for `additional` more values. + /// + /// Computes in **O(n)** time. + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Shrink the capacity of the set as much as possible. + /// + /// Computes in **O(n)** time. + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Insert the value into the set. + /// + /// If an equivalent item already exists in the set, it returns + /// `false` leaving the original value in the set and without + /// altering its insertion order. Otherwise, it inserts the new + /// item and returns `true`. + /// + /// Computes in **O(1)** time (amortized average). + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Insert the value into the set, and get its index. + /// + /// If an equivalent item already exists in the set, it returns + /// the index of the existing item and `false`, leaving the + /// original value in the set and without altering its insertion + /// order. Otherwise, it inserts the new item and returns the index + /// of the inserted item and `true`. + /// + /// Computes in **O(1)** time (amortized average). + pub fn insert_full(&mut self, value: T) -> (usize, bool) { + use super::map::Entry::*; + + match self.map.entry(value) { + Occupied(e) => (e.index(), false), + Vacant(e) => { + let index = e.index(); + e.insert(()); + (index, true) + } + } + } + + /// Return an iterator over the values that are in `self` but not `other`. + /// + /// Values are produced in the same order that they appear in `self`. + pub fn difference<'a, S2>(&'a self, other: &'a IndexSet) -> Difference<'a, T, S2> + where + S2: BuildHasher, + { + Difference { + iter: self.iter(), + other, + } + } + + /// Return an iterator over the values that are in `self` or `other`, + /// but not in both. + /// + /// Values from `self` are produced in their original order, followed by + /// values from `other` in their original order. + pub fn symmetric_difference<'a, S2>( + &'a self, + other: &'a IndexSet, + ) -> SymmetricDifference<'a, T, S, S2> + where + S2: BuildHasher, + { + SymmetricDifference { + iter: self.difference(other).chain(other.difference(self)), + } + } + + /// Return an iterator over the values that are in both `self` and `other`. + /// + /// Values are produced in the same order that they appear in `self`. + pub fn intersection<'a, S2>(&'a self, other: &'a IndexSet) -> Intersection<'a, T, S2> + where + S2: BuildHasher, + { + Intersection { + iter: self.iter(), + other, + } + } + + /// Return an iterator over all values that are in `self` or `other`. + /// + /// Values from `self` are produced in their original order, followed by + /// values that are unique to `other` in their original order. + pub fn union<'a, S2>(&'a self, other: &'a IndexSet) -> Union<'a, T, S> + where + S2: BuildHasher, + { + Union { + iter: self.iter().chain(other.difference(self)), + } + } + + /// Return `true` if an equivalent to `value` exists in the set. + /// + /// Computes in **O(1)** time (average). + pub fn contains(&self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.map.contains_key(value) + } + + /// Return a reference to the value stored in the set, if it is present, + /// else `None`. + /// + /// Computes in **O(1)** time (average). + pub fn get(&self, value: &Q) -> Option<&T> + where + Q: Hash + Equivalent, + { + self.map.get_key_value(value).map(|(x, &())| x) + } + + /// Return item index and value + pub fn get_full(&self, value: &Q) -> Option<(usize, &T)> + where + Q: Hash + Equivalent, + { + self.map.get_full(value).map(|(i, x, &())| (i, x)) + } + + /// Return item index, if it exists in the set + pub fn get_index_of(&self, value: &Q) -> Option + where + Q: Hash + Equivalent, + { + self.map.get_index_of(value) + } + + /// Adds a value to the set, replacing the existing value, if any, that is + /// equal to the given one, without altering its insertion order. Returns + /// the replaced value. + /// + /// Computes in **O(1)** time (average). + pub fn replace(&mut self, value: T) -> Option { + self.replace_full(value).1 + } + + /// Adds a value to the set, replacing the existing value, if any, that is + /// equal to the given one, without altering its insertion order. Returns + /// the index of the item and its replaced value. + /// + /// Computes in **O(1)** time (average). + pub fn replace_full(&mut self, value: T) -> (usize, Option) { + use super::map::Entry::*; + + match self.map.entry(value) { + Vacant(e) => { + let index = e.index(); + e.insert(()); + (index, None) + } + Occupied(e) => (e.index(), Some(e.replace_key())), + } + } + + /// Remove the value from the set, and return `true` if it was present. + /// + /// **NOTE:** This is equivalent to `.swap_remove(value)`, if you want + /// to preserve the order of the values in the set, use `.shift_remove(value)`. + /// + /// Computes in **O(1)** time (average). + pub fn remove(&mut self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.swap_remove(value) + } + + /// Remove the value from the set, and return `true` if it was present. + /// + /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `false` if `value` was not in the set. + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove(&mut self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.map.swap_remove(value).is_some() + } + + /// Remove the value from the set, and return `true` if it was present. + /// + /// Like `Vec::remove`, the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `false` if `value` was not in the set. + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove(&mut self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.map.shift_remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the + /// given one. + /// + /// **NOTE:** This is equivalent to `.swap_take(value)`, if you need to + /// preserve the order of the values in the set, use `.shift_take(value)` + /// instead. + /// + /// Computes in **O(1)** time (average). + pub fn take(&mut self, value: &Q) -> Option + where + Q: Hash + Equivalent, + { + self.swap_take(value) + } + + /// Removes and returns the value in the set, if any, that is equal to the + /// given one. + /// + /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `value` was not in the set. + /// + /// Computes in **O(1)** time (average). + pub fn swap_take(&mut self, value: &Q) -> Option + where + Q: Hash + Equivalent, + { + self.map.swap_remove_entry(value).map(|(x, ())| x) + } + + /// Removes and returns the value in the set, if any, that is equal to the + /// given one. + /// + /// Like `Vec::remove`, the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `value` was not in the set. + /// + /// Computes in **O(n)** time (average). + pub fn shift_take(&mut self, value: &Q) -> Option + where + Q: Hash + Equivalent, + { + self.map.shift_remove_entry(value).map(|(x, ())| x) + } + + /// Remove the value from the set return it and the index it had. + /// + /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Return `None` if `value` was not in the set. + pub fn swap_remove_full(&mut self, value: &Q) -> Option<(usize, T)> + where + Q: Hash + Equivalent, + { + self.map.swap_remove_full(value).map(|(i, x, ())| (i, x)) + } + + /// Remove the value from the set return it and the index it had. + /// + /// Like `Vec::remove`, the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Return `None` if `value` was not in the set. + pub fn shift_remove_full(&mut self, value: &Q) -> Option<(usize, T)> + where + Q: Hash + Equivalent, + { + self.map.shift_remove_full(value).map(|(i, x, ())| (i, x)) + } + + /// Remove the last value + /// + /// This preserves the order of the remaining elements. + /// + /// Computes in **O(1)** time (average). + pub fn pop(&mut self) -> Option { + self.map.pop().map(|(x, ())| x) + } + + /// Scan through each value in the set and keep those where the + /// closure `keep` returns `true`. + /// + /// The elements are visited in order, and remaining elements keep their + /// order. + /// + /// Computes in **O(n)** time (average). + pub fn retain(&mut self, mut keep: F) + where + F: FnMut(&T) -> bool, + { + self.map.retain(move |x, &mut ()| keep(x)) + } + + /// Sort the set’s values by their default ordering. + /// + /// See [`sort_by`](Self::sort_by) for details. + pub fn sort(&mut self) + where + T: Ord, + { + self.map.sort_keys() + } + + /// Sort the set’s values in place using the comparison function `cmp`. + /// + /// Computes in **O(n log n)** time and **O(n)** space. The sort is stable. + pub fn sort_by(&mut self, mut cmp: F) + where + F: FnMut(&T, &T) -> Ordering, + { + self.map.sort_by(move |a, _, b, _| cmp(a, b)); + } + + /// Sort the values of the set and return a by-value iterator of + /// the values with the result. + /// + /// The sort is stable. + pub fn sorted_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&T, &T) -> Ordering, + { + IntoIter { + iter: self.map.sorted_by(move |a, _, b, _| cmp(a, b)).iter, + } + } + + /// Sort the set's values by their default ordering. + /// + /// See [`sort_unstable_by`](Self::sort_unstable_by) for details. + pub fn sort_unstable(&mut self) + where + T: Ord, + { + self.map.sort_unstable_keys() + } + + /// Sort the set's values in place using the comparison funtion `cmp`. + /// + /// Computes in **O(n log n)** time. The sort is unstable. + pub fn sort_unstable_by(&mut self, mut cmp: F) + where + F: FnMut(&T, &T) -> Ordering, + { + self.map.sort_unstable_by(move |a, _, b, _| cmp(a, b)) + } + + /// Sort the values of the set and return a by-value iterator of + /// the values with the result. + pub fn sorted_unstable_by(self, mut cmp: F) -> IntoIter + where + F: FnMut(&T, &T) -> Ordering, + { + IntoIter { + iter: self + .map + .sorted_unstable_by(move |a, _, b, _| cmp(a, b)) + .iter, + } + } + + /// Reverses the order of the set’s values in place. + /// + /// Computes in **O(n)** time and **O(1)** space. + pub fn reverse(&mut self) { + self.map.reverse() + } +} + +impl IndexSet { + /// Get a value by index + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Computes in **O(1)** time. + pub fn get_index(&self, index: usize) -> Option<&T> { + self.as_entries().get(index).map(Bucket::key_ref) + } + + /// Get the first value + /// + /// Computes in **O(1)** time. + pub fn first(&self) -> Option<&T> { + self.as_entries().first().map(Bucket::key_ref) + } + + /// Get the last value + /// + /// Computes in **O(1)** time. + pub fn last(&self) -> Option<&T> { + self.as_entries().last().map(Bucket::key_ref) + } + + /// Remove the value by index + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Like `Vec::swap_remove`, the value is removed by swapping it with the + /// last element of the set and popping it off. **This perturbs + /// the position of what used to be the last element!** + /// + /// Computes in **O(1)** time (average). + pub fn swap_remove_index(&mut self, index: usize) -> Option { + self.map.swap_remove_index(index).map(|(x, ())| x) + } + + /// Remove the value by index + /// + /// Valid indices are *0 <= index < self.len()* + /// + /// Like `Vec::remove`, the value is removed by shifting all of the + /// elements that follow it, preserving their relative order. + /// **This perturbs the index of all of those elements!** + /// + /// Computes in **O(n)** time (average). + pub fn shift_remove_index(&mut self, index: usize) -> Option { + self.map.shift_remove_index(index).map(|(x, ())| x) + } + + /// Swaps the position of two values in the set. + /// + /// ***Panics*** if `a` or `b` are out of bounds. + pub fn swap_indices(&mut self, a: usize, b: usize) { + self.map.swap_indices(a, b) + } +} + +/// Access `IndexSet` values at indexed positions. +/// +/// # Examples +/// +/// ``` +/// use indexmap::IndexSet; +/// +/// let mut set = IndexSet::new(); +/// for word in "Lorem ipsum dolor sit amet".split_whitespace() { +/// set.insert(word.to_string()); +/// } +/// assert_eq!(set[0], "Lorem"); +/// assert_eq!(set[1], "ipsum"); +/// set.reverse(); +/// assert_eq!(set[0], "amet"); +/// assert_eq!(set[1], "sit"); +/// set.sort(); +/// assert_eq!(set[0], "Lorem"); +/// assert_eq!(set[1], "amet"); +/// ``` +/// +/// ```should_panic +/// use indexmap::IndexSet; +/// +/// let mut set = IndexSet::new(); +/// set.insert("foo"); +/// println!("{:?}", set[10]); // panics! +/// ``` +impl Index for IndexSet { + type Output = T; + + /// Returns a reference to the value at the supplied `index`. + /// + /// ***Panics*** if `index` is out of bounds. + fn index(&self, index: usize) -> &T { + self.get_index(index) + .expect("IndexSet: index out of bounds") + } +} + +/// An owning iterator over the items of a `IndexSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`IndexSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`IndexSet`]: struct.IndexSet.html +/// [`into_iter`]: struct.IndexSet.html#method.into_iter +pub struct IntoIter { + iter: vec::IntoIter>, +} + +impl Iterator for IntoIter { + type Item = T; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for IntoIter { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +/// An iterator over the items of a `IndexSet`. +/// +/// This `struct` is created by the [`iter`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: struct.IndexSet.html +/// [`iter`]: struct.IndexSet.html#method.iter +pub struct Iter<'a, T> { + iter: slice::Iter<'a, Bucket>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + iterator_methods!(Bucket::key_ref); +} + +impl DoubleEndedIterator for Iter<'_, T> { + double_ended_iterator_methods!(Bucket::key_ref); +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A draining iterator over the items of a `IndexSet`. +/// +/// This `struct` is created by the [`drain`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: struct.IndexSet.html +/// [`drain`]: struct.IndexSet.html#method.drain +pub struct Drain<'a, T> { + iter: vec::Drain<'a, Bucket>, +} + +impl Iterator for Drain<'_, T> { + type Item = T; + + iterator_methods!(Bucket::key); +} + +impl DoubleEndedIterator for Drain<'_, T> { + double_ended_iterator_methods!(Bucket::key); +} + +impl ExactSizeIterator for Drain<'_, T> { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl FusedIterator for Drain<'_, T> {} + +impl fmt::Debug for Drain<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = self.iter.as_slice().iter().map(Bucket::key_ref); + f.debug_list().entries(iter).finish() + } +} + +impl<'a, T, S> IntoIterator for &'a IndexSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for IndexSet { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { + iter: self.map.into_iter().iter, + } + } +} + +impl FromIterator for IndexSet +where + T: Hash + Eq, + S: BuildHasher + Default, +{ + fn from_iter>(iterable: I) -> Self { + let iter = iterable.into_iter().map(|x| (x, ())); + IndexSet { + map: IndexMap::from_iter(iter), + } + } +} + +#[cfg(all(has_std, rustc_1_51))] +impl From<[T; N]> for IndexSet +where + T: Eq + Hash, +{ + /// # Examples + /// + /// ``` + /// use indexmap::IndexSet; + /// + /// let set1 = IndexSet::from([1, 2, 3, 4]); + /// let set2: IndexSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + std::array::IntoIter::new(arr).collect() + } +} + +impl Extend for IndexSet +where + T: Hash + Eq, + S: BuildHasher, +{ + fn extend>(&mut self, iterable: I) { + let iter = iterable.into_iter().map(|x| (x, ())); + self.map.extend(iter); + } +} + +impl<'a, T, S> Extend<&'a T> for IndexSet +where + T: Hash + Eq + Copy + 'a, + S: BuildHasher, +{ + fn extend>(&mut self, iterable: I) { + let iter = iterable.into_iter().copied(); + self.extend(iter); + } +} + +impl Default for IndexSet +where + S: Default, +{ + /// Return an empty `IndexSet` + fn default() -> Self { + IndexSet { + map: IndexMap::default(), + } + } +} + +impl PartialEq> for IndexSet +where + T: Hash + Eq, + S1: BuildHasher, + S2: BuildHasher, +{ + fn eq(&self, other: &IndexSet) -> bool { + self.len() == other.len() && self.is_subset(other) + } +} + +impl Eq for IndexSet +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl IndexSet +where + T: Eq + Hash, + S: BuildHasher, +{ + /// Returns `true` if `self` has no elements in common with `other`. + pub fn is_disjoint(&self, other: &IndexSet) -> bool + where + S2: BuildHasher, + { + if self.len() <= other.len() { + self.iter().all(move |value| !other.contains(value)) + } else { + other.iter().all(move |value| !self.contains(value)) + } + } + + /// Returns `true` if all elements of `self` are contained in `other`. + pub fn is_subset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher, + { + self.len() <= other.len() && self.iter().all(move |value| other.contains(value)) + } + + /// Returns `true` if all elements of `other` are contained in `self`. + pub fn is_superset(&self, other: &IndexSet) -> bool + where + S2: BuildHasher, + { + other.is_subset(self) + } +} + +/// A lazy iterator producing elements in the difference of `IndexSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: struct.IndexSet.html +/// [`difference`]: struct.IndexSet.html#method.difference +pub struct Difference<'a, T, S> { + iter: Iter<'a, T>, + other: &'a IndexSet, +} + +impl<'a, T, S> Iterator for Difference<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + while let Some(item) = self.iter.next() { + if !self.other.contains(item) { + return Some(item); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} + +impl DoubleEndedIterator for Difference<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + while let Some(item) = self.iter.next_back() { + if !self.other.contains(item) { + return Some(item); + } + } + None + } +} + +impl FusedIterator for Difference<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Difference<'_, T, S> { + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl fmt::Debug for Difference<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the intersection of `IndexSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: struct.IndexSet.html +/// [`intersection`]: struct.IndexSet.html#method.intersection +pub struct Intersection<'a, T, S> { + iter: Iter<'a, T>, + other: &'a IndexSet, +} + +impl<'a, T, S> Iterator for Intersection<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + while let Some(item) = self.iter.next() { + if self.other.contains(item) { + return Some(item); + } + } + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, self.iter.size_hint().1) + } +} + +impl DoubleEndedIterator for Intersection<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + while let Some(item) = self.iter.next_back() { + if self.other.contains(item) { + return Some(item); + } + } + None + } +} + +impl FusedIterator for Intersection<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Intersection<'_, T, S> { + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl fmt::Debug for Intersection<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the symmetric difference of `IndexSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`IndexSet`]. See its documentation for more. +/// +/// [`IndexSet`]: struct.IndexSet.html +/// [`symmetric_difference`]: struct.IndexSet.html#method.symmetric_difference +pub struct SymmetricDifference<'a, T, S1, S2> { + iter: Chain, Difference<'a, T, S1>>, +} + +impl<'a, T, S1, S2> Iterator for SymmetricDifference<'a, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl DoubleEndedIterator for SymmetricDifference<'_, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.iter.next_back() + } + + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.rfold(init, f) + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S1, S2> +where + T: Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ +} + +impl Clone for SymmetricDifference<'_, T, S1, S2> { + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for SymmetricDifference<'_, T, S1, S2> +where + T: fmt::Debug + Eq + Hash, + S1: BuildHasher, + S2: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A lazy iterator producing elements in the union of `IndexSet`s. +/// +/// This `struct` is created by the [`union`] method on [`IndexSet`]. +/// See its documentation for more. +/// +/// [`IndexSet`]: struct.IndexSet.html +/// [`union`]: struct.IndexSet.html#method.union +pub struct Union<'a, T, S> { + iter: Chain, Difference<'a, T, S>>, +} + +impl<'a, T, S> Iterator for Union<'a, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + type Item = &'a T; + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl DoubleEndedIterator for Union<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ + fn next_back(&mut self) -> Option { + self.iter.next_back() + } + + fn rfold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.rfold(init, f) + } +} + +impl FusedIterator for Union<'_, T, S> +where + T: Eq + Hash, + S: BuildHasher, +{ +} + +impl Clone for Union<'_, T, S> { + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl fmt::Debug for Union<'_, T, S> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl BitAnd<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set intersection, cloned into a new set. + /// + /// Values are collected in the same order that they appear in `self`. + fn bitand(self, other: &IndexSet) -> Self::Output { + self.intersection(other).cloned().collect() + } +} + +impl BitOr<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set union, cloned into a new set. + /// + /// Values from `self` are collected in their original order, followed by + /// values that are unique to `other` in their original order. + fn bitor(self, other: &IndexSet) -> Self::Output { + self.union(other).cloned().collect() + } +} + +impl BitXor<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set symmetric-difference, cloned into a new set. + /// + /// Values from `self` are collected in their original order, followed by + /// values from `other` in their original order. + fn bitxor(self, other: &IndexSet) -> Self::Output { + self.symmetric_difference(other).cloned().collect() + } +} + +impl Sub<&IndexSet> for &IndexSet +where + T: Eq + Hash + Clone, + S1: BuildHasher + Default, + S2: BuildHasher, +{ + type Output = IndexSet; + + /// Returns the set difference, cloned into a new set. + /// + /// Values are collected in the same order that they appear in `self`. + fn sub(self, other: &IndexSet) -> Self::Output { + self.difference(other).cloned().collect() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::enumerate; + use std::string::String; + + #[test] + fn it_works() { + let mut set = IndexSet::new(); + assert_eq!(set.is_empty(), true); + set.insert(1); + set.insert(1); + assert_eq!(set.len(), 1); + assert!(set.get(&1).is_some()); + assert_eq!(set.is_empty(), false); + } + + #[test] + fn new() { + let set = IndexSet::::new(); + println!("{:?}", set); + assert_eq!(set.capacity(), 0); + assert_eq!(set.len(), 0); + assert_eq!(set.is_empty(), true); + } + + #[test] + fn insert() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in enumerate(&insert) { + assert_eq!(set.len(), i); + set.insert(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + println!("{:?}", set); + + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } + } + + #[test] + fn insert_full() { + let insert = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in enumerate(&insert) { + assert_eq!(set.len(), i); + let (index, success) = set.insert_full(elt); + assert!(success); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), i + 1); + } + + let len = set.len(); + for &elt in &present { + let (index, success) = set.insert_full(elt); + assert!(!success); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), len); + } + } + + #[test] + fn insert_2() { + let mut set = IndexSet::with_capacity(16); + + let mut values = vec![]; + values.extend(0..16); + values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &values { + let old_set = set.clone(); + set.insert(i); + for value in old_set.iter() { + if set.get(value).is_none() { + println!("old_set: {:?}", old_set); + println!("set: {:?}", set); + panic!("did not find {} in set", value); + } + } + } + + for &i in &values { + assert!(set.get(&i).is_some(), "did not find {}", i); + } + } + + #[test] + fn insert_dup() { + let mut elements = vec![0, 2, 4, 6, 8]; + let mut set: IndexSet = elements.drain(..).collect(); + { + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + { + let inserted = set.insert(0); + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(inserted, false); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + } + + #[test] + fn insert_order() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..insert.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } + } + + #[test] + fn replace() { + let replace = [0, 4, 2, 12, 8, 7, 11, 5]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(replace.len()); + + for (i, &elt) in enumerate(&replace) { + assert_eq!(set.len(), i); + set.replace(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + println!("{:?}", set); + + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } + } + + #[test] + fn replace_full() { + let replace = vec![9, 2, 7, 1, 4, 6, 13]; + let present = vec![1, 6, 2]; + let mut set = IndexSet::with_capacity(replace.len()); + + for (i, &elt) in enumerate(&replace) { + assert_eq!(set.len(), i); + let (index, replaced) = set.replace_full(elt); + assert!(replaced.is_none()); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), i + 1); + } + + let len = set.len(); + for &elt in &present { + let (index, replaced) = set.replace_full(elt); + assert_eq!(Some(elt), replaced); + assert_eq!(Some(index), set.get_full(&elt).map(|x| x.0)); + assert_eq!(set.len(), len); + } + } + + #[test] + fn replace_2() { + let mut set = IndexSet::with_capacity(16); + + let mut values = vec![]; + values.extend(0..16); + values.extend(if cfg!(miri) { 32..64 } else { 128..267 }); + + for &i in &values { + let old_set = set.clone(); + set.replace(i); + for value in old_set.iter() { + if set.get(value).is_none() { + println!("old_set: {:?}", old_set); + println!("set: {:?}", set); + panic!("did not find {} in set", value); + } + } + } + + for &i in &values { + assert!(set.get(&i).is_some(), "did not find {}", i); + } + } + + #[test] + fn replace_dup() { + let mut elements = vec![0, 2, 4, 6, 8]; + let mut set: IndexSet = elements.drain(..).collect(); + { + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + { + let replaced = set.replace(0); + let (i, v) = set.get_full(&0).unwrap(); + assert_eq!(set.len(), 5); + assert_eq!(replaced, Some(0)); + assert_eq!(i, 0); + assert_eq!(*v, 0); + } + } + + #[test] + fn replace_order() { + let replace = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &replace { + set.replace(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), replace.len()); + for (a, b) in replace.iter().zip(set.iter()) { + assert_eq!(a, b); + } + for (i, v) in (0..replace.len()).zip(set.iter()) { + assert_eq!(set.get_index(i).unwrap(), v); + } + } + + #[test] + fn grow() { + let insert = [0, 4, 2, 12, 8, 7, 11]; + let not_present = [1, 3, 6, 9, 10]; + let mut set = IndexSet::with_capacity(insert.len()); + + for (i, &elt) in enumerate(&insert) { + assert_eq!(set.len(), i); + set.insert(elt); + assert_eq!(set.len(), i + 1); + assert_eq!(set.get(&elt), Some(&elt)); + } + + println!("{:?}", set); + for &elt in &insert { + set.insert(elt * 10); + } + for &elt in &insert { + set.insert(elt * 100); + } + for (i, &elt) in insert.iter().cycle().enumerate().take(100) { + set.insert(elt * 100 + i as i32); + } + println!("{:?}", set); + for &elt in ¬_present { + assert!(set.get(&elt).is_none()); + } + } + + #[test] + fn reserve() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + set.reserve(100); + let capacity = set.capacity(); + assert!(capacity >= 100); + for i in 0..capacity { + assert_eq!(set.len(), i); + set.insert(i); + assert_eq!(set.len(), i + 1); + assert_eq!(set.capacity(), capacity); + assert_eq!(set.get(&i), Some(&i)); + } + set.insert(capacity); + assert_eq!(set.len(), capacity + 1); + assert!(set.capacity() > capacity); + assert_eq!(set.get(&capacity), Some(&capacity)); + } + + #[test] + fn shrink_to_fit() { + let mut set = IndexSet::::new(); + assert_eq!(set.capacity(), 0); + for i in 0..100 { + assert_eq!(set.len(), i); + set.insert(i); + assert_eq!(set.len(), i + 1); + assert!(set.capacity() >= i + 1); + assert_eq!(set.get(&i), Some(&i)); + set.shrink_to_fit(); + assert_eq!(set.len(), i + 1); + assert_eq!(set.capacity(), i + 1); + assert_eq!(set.get(&i), Some(&i)); + } + } + + #[test] + fn remove() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + assert_eq!(set.iter().count(), set.len()); + assert_eq!(set.iter().count(), insert.len()); + for (a, b) in insert.iter().zip(set.iter()) { + assert_eq!(a, b); + } + + let remove_fail = [99, 77]; + let remove = [4, 12, 8, 7]; + + for &value in &remove_fail { + assert!(set.swap_remove_full(&value).is_none()); + } + println!("{:?}", set); + for &value in &remove { + //println!("{:?}", set); + let index = set.get_full(&value).unwrap().0; + assert_eq!(set.swap_remove_full(&value), Some((index, value))); + } + println!("{:?}", set); + + for value in &insert { + assert_eq!(set.get(value).is_some(), !remove.contains(value)); + } + assert_eq!(set.len(), insert.len() - remove.len()); + assert_eq!(set.iter().count(), insert.len() - remove.len()); + } + + #[test] + fn swap_remove_index() { + let insert = [0, 4, 2, 12, 8, 7, 11, 5, 3, 17, 19, 22, 23]; + let mut set = IndexSet::new(); + + for &elt in &insert { + set.insert(elt); + } + + let mut vector = insert.to_vec(); + let remove_sequence = &[3, 3, 10, 4, 5, 4, 3, 0, 1]; + + // check that the same swap remove sequence on vec and set + // have the same result. + for &rm in remove_sequence { + let out_vec = vector.swap_remove(rm); + let out_set = set.swap_remove_index(rm).unwrap(); + assert_eq!(out_vec, out_set); + } + assert_eq!(vector.len(), set.len()); + for (a, b) in vector.iter().zip(set.iter()) { + assert_eq!(a, b); + } + } + + #[test] + fn partial_eq_and_eq() { + let mut set_a = IndexSet::new(); + set_a.insert(1); + set_a.insert(2); + let mut set_b = set_a.clone(); + assert_eq!(set_a, set_b); + set_b.swap_remove(&1); + assert_ne!(set_a, set_b); + + let set_c: IndexSet<_> = set_b.into_iter().collect(); + assert_ne!(set_a, set_c); + assert_ne!(set_c, set_a); + } + + #[test] + fn extend() { + let mut set = IndexSet::new(); + set.extend(vec![&1, &2, &3, &4]); + set.extend(vec![5, 6]); + assert_eq!(set.into_iter().collect::>(), vec![1, 2, 3, 4, 5, 6]); + } + + #[test] + fn comparisons() { + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).collect(); + + assert!(!set_a.is_disjoint(&set_a)); + assert!(set_a.is_subset(&set_a)); + assert!(set_a.is_superset(&set_a)); + + assert!(set_a.is_disjoint(&set_b)); + assert!(set_b.is_disjoint(&set_a)); + assert!(!set_a.is_subset(&set_b)); + assert!(!set_b.is_subset(&set_a)); + assert!(!set_a.is_superset(&set_b)); + assert!(!set_b.is_superset(&set_a)); + + assert!(!set_a.is_disjoint(&set_c)); + assert!(!set_c.is_disjoint(&set_a)); + assert!(set_a.is_subset(&set_c)); + assert!(!set_c.is_subset(&set_a)); + assert!(!set_a.is_superset(&set_c)); + assert!(set_c.is_superset(&set_a)); + + assert!(!set_c.is_disjoint(&set_d)); + assert!(!set_d.is_disjoint(&set_c)); + assert!(!set_c.is_subset(&set_d)); + assert!(!set_d.is_subset(&set_c)); + assert!(!set_c.is_superset(&set_d)); + assert!(!set_d.is_superset(&set_c)); + } + + #[test] + fn iter_comparisons() { + use std::iter::empty; + + fn check<'a, I1, I2>(iter1: I1, iter2: I2) + where + I1: Iterator, + I2: Iterator, + { + assert!(iter1.copied().eq(iter2)); + } + + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + check(set_a.difference(&set_a), empty()); + check(set_a.symmetric_difference(&set_a), empty()); + check(set_a.intersection(&set_a), 0..3); + check(set_a.union(&set_a), 0..3); + + check(set_a.difference(&set_b), 0..3); + check(set_b.difference(&set_a), 3..6); + check(set_a.symmetric_difference(&set_b), 0..6); + check(set_b.symmetric_difference(&set_a), (3..6).chain(0..3)); + check(set_a.intersection(&set_b), empty()); + check(set_b.intersection(&set_a), empty()); + check(set_a.union(&set_b), 0..6); + check(set_b.union(&set_a), (3..6).chain(0..3)); + + check(set_a.difference(&set_c), empty()); + check(set_c.difference(&set_a), 3..6); + check(set_a.symmetric_difference(&set_c), 3..6); + check(set_c.symmetric_difference(&set_a), 3..6); + check(set_a.intersection(&set_c), 0..3); + check(set_c.intersection(&set_a), 0..3); + check(set_a.union(&set_c), 0..6); + check(set_c.union(&set_a), 0..6); + + check(set_c.difference(&set_d), 0..3); + check(set_d.difference(&set_c), (6..9).rev()); + check( + set_c.symmetric_difference(&set_d), + (0..3).chain((6..9).rev()), + ); + check(set_d.symmetric_difference(&set_c), (6..9).rev().chain(0..3)); + check(set_c.intersection(&set_d), 3..6); + check(set_d.intersection(&set_c), (3..6).rev()); + check(set_c.union(&set_d), (0..6).chain((6..9).rev())); + check(set_d.union(&set_c), (3..9).rev().chain(0..3)); + } + + #[test] + fn ops() { + let empty = IndexSet::::new(); + let set_a: IndexSet<_> = (0..3).collect(); + let set_b: IndexSet<_> = (3..6).collect(); + let set_c: IndexSet<_> = (0..6).collect(); + let set_d: IndexSet<_> = (3..9).rev().collect(); + + #[allow(clippy::eq_op)] + { + assert_eq!(&set_a & &set_a, set_a); + assert_eq!(&set_a | &set_a, set_a); + assert_eq!(&set_a ^ &set_a, empty); + assert_eq!(&set_a - &set_a, empty); + } + + assert_eq!(&set_a & &set_b, empty); + assert_eq!(&set_b & &set_a, empty); + assert_eq!(&set_a | &set_b, set_c); + assert_eq!(&set_b | &set_a, set_c); + assert_eq!(&set_a ^ &set_b, set_c); + assert_eq!(&set_b ^ &set_a, set_c); + assert_eq!(&set_a - &set_b, set_a); + assert_eq!(&set_b - &set_a, set_b); + + assert_eq!(&set_a & &set_c, set_a); + assert_eq!(&set_c & &set_a, set_a); + assert_eq!(&set_a | &set_c, set_c); + assert_eq!(&set_c | &set_a, set_c); + assert_eq!(&set_a ^ &set_c, set_b); + assert_eq!(&set_c ^ &set_a, set_b); + assert_eq!(&set_a - &set_c, empty); + assert_eq!(&set_c - &set_a, set_b); + + assert_eq!(&set_c & &set_d, set_b); + assert_eq!(&set_d & &set_c, set_b); + assert_eq!(&set_c | &set_d, &set_a | &set_d); + assert_eq!(&set_d | &set_c, &set_a | &set_d); + assert_eq!(&set_c ^ &set_d, &set_a | &(&set_d - &set_b)); + assert_eq!(&set_d ^ &set_c, &set_a | &(&set_d - &set_b)); + assert_eq!(&set_c - &set_d, set_a); + assert_eq!(&set_d - &set_c, &set_d - &set_b); + } + + #[test] + #[cfg(all(has_std, rustc_1_51))] + fn from_array() { + let set1 = IndexSet::from([1, 2, 3, 4]); + let set2: IndexSet<_> = [1, 2, 3, 4].into(); + + assert_eq!(set1, set2); + } +} diff --git a/third_party/rust/indexmap/v1/crate/src/util.rs b/third_party/rust/indexmap/v1/crate/src/util.rs new file mode 100644 index 000000000000..5388f470cf08 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/src/util.rs @@ -0,0 +1,39 @@ +use core::iter::Enumerate; +use core::ops::{Bound, Range, RangeBounds}; + +pub(crate) fn third(t: (A, B, C)) -> C { + t.2 +} + +pub(crate) fn enumerate(iterable: I) -> Enumerate +where + I: IntoIterator, +{ + iterable.into_iter().enumerate() +} + +pub(crate) fn simplify_range(range: R, len: usize) -> Range +where + R: RangeBounds, +{ + let start = match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(&i) if i <= len => i, + Bound::Excluded(&i) if i < len => i + 1, + bound => panic!("range start {:?} should be <= length {}", bound, len), + }; + let end = match range.end_bound() { + Bound::Unbounded => len, + Bound::Excluded(&i) if i <= len => i, + Bound::Included(&i) if i < len => i + 1, + bound => panic!("range end {:?} should be <= length {}", bound, len), + }; + if start > end { + panic!( + "range start {:?} should be <= range end {:?}", + range.start_bound(), + range.end_bound() + ); + } + start..end +} diff --git a/third_party/rust/indexmap/v1/crate/tests/equivalent_trait.rs b/third_party/rust/indexmap/v1/crate/tests/equivalent_trait.rs new file mode 100644 index 000000000000..ff5943a3edb8 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/tests/equivalent_trait.rs @@ -0,0 +1,53 @@ +use indexmap::indexmap; +use indexmap::Equivalent; + +use std::hash::Hash; + +#[derive(Debug, Hash)] +pub struct Pair(pub A, pub B); + +impl PartialEq<(A, B)> for Pair +where + C: PartialEq, + D: PartialEq, +{ + fn eq(&self, rhs: &(A, B)) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } +} + +impl Equivalent for Pair +where + Pair: PartialEq, + A: Hash + Eq, + B: Hash + Eq, +{ + fn equivalent(&self, other: &X) -> bool { + *self == *other + } +} + +#[test] +fn test_lookup() { + let s = String::from; + let map = indexmap! { + (s("a"), s("b")) => 1, + (s("a"), s("x")) => 2, + }; + + assert!(map.contains_key(&Pair("a", "b"))); + assert!(!map.contains_key(&Pair("b", "a"))); +} + +#[test] +fn test_string_str() { + let s = String::from; + let mut map = indexmap! { + s("a") => 1, s("b") => 2, + s("x") => 3, s("y") => 4, + }; + + assert!(map.contains_key("a")); + assert!(!map.contains_key("z")); + assert_eq!(map.swap_remove("b"), Some(2)); +} diff --git a/third_party/rust/indexmap/v1/crate/tests/macros_full_path.rs b/third_party/rust/indexmap/v1/crate/tests/macros_full_path.rs new file mode 100644 index 000000000000..2467d9b4f5d4 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/tests/macros_full_path.rs @@ -0,0 +1,19 @@ +#[test] +fn test_create_map() { + let _m = indexmap::indexmap! { + 1 => 2, + 7 => 1, + 2 => 2, + 3 => 3, + }; +} + +#[test] +fn test_create_set() { + let _s = indexmap::indexset! { + 1, + 7, + 2, + 3, + }; +} diff --git a/third_party/rust/indexmap/v1/crate/tests/quick.rs b/third_party/rust/indexmap/v1/crate/tests/quick.rs new file mode 100644 index 000000000000..6c6cc03453d8 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/tests/quick.rs @@ -0,0 +1,527 @@ +use indexmap::{IndexMap, IndexSet}; +use itertools::Itertools; + +use quickcheck::Arbitrary; +use quickcheck::Gen; +use quickcheck::QuickCheck; +use quickcheck::TestResult; + +use fnv::FnvHasher; +use std::hash::{BuildHasher, BuildHasherDefault}; +type FnvBuilder = BuildHasherDefault; +type IndexMapFnv = IndexMap; + +use std::cmp::min; +use std::collections::HashMap; +use std::collections::HashSet; +use std::fmt::Debug; +use std::hash::Hash; +use std::iter::FromIterator; +use std::ops::Bound; +use std::ops::Deref; + +use indexmap::map::Entry as OEntry; +use std::collections::hash_map::Entry as HEntry; + +fn set<'a, T: 'a, I>(iter: I) -> HashSet +where + I: IntoIterator, + T: Copy + Hash + Eq, +{ + iter.into_iter().copied().collect() +} + +fn indexmap<'a, T: 'a, I>(iter: I) -> IndexMap +where + I: IntoIterator, + T: Copy + Hash + Eq, +{ + IndexMap::from_iter(iter.into_iter().copied().map(|k| (k, ()))) +} + +// Helper macro to allow us to use smaller quickcheck limits under miri. +macro_rules! quickcheck_limit { + (@as_items $($i:item)*) => ($($i)*); + { + $( + $(#[$m:meta])* + fn $fn_name:ident($($arg_name:ident : $arg_ty:ty),*) -> $ret:ty { + $($code:tt)* + } + )* + } => ( + quickcheck::quickcheck! { + @as_items + $( + #[test] + $(#[$m])* + fn $fn_name() { + fn prop($($arg_name: $arg_ty),*) -> $ret { + $($code)* + } + let mut quickcheck = QuickCheck::new(); + if cfg!(miri) { + quickcheck = quickcheck + .gen(Gen::new(10)) + .tests(10) + .max_tests(100); + } + + quickcheck.quickcheck(prop as fn($($arg_ty),*) -> $ret); + } + )* + } + ) +} + +quickcheck_limit! { + fn contains(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + insert.iter().all(|&key| map.get(&key).is_some()) + } + + fn contains_not(insert: Vec, not: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let nots = &set(¬) - &set(&insert); + nots.iter().all(|&key| map.get(&key).is_none()) + } + + fn insert_remove(insert: Vec, remove: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + for &key in &remove { + map.swap_remove(&key); + } + let elements = &set(&insert) - &set(&remove); + map.len() == elements.len() && map.iter().count() == elements.len() && + elements.iter().all(|k| map.get(k).is_some()) + } + + fn insertion_order(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + itertools::assert_equal(insert.iter().unique(), map.keys()); + true + } + + fn pop(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let mut pops = Vec::new(); + while let Some((key, _v)) = map.pop() { + pops.push(key); + } + pops.reverse(); + + itertools::assert_equal(insert.iter().unique(), &pops); + true + } + + fn with_cap(template: Vec<()>) -> bool { + let cap = template.len(); + let map: IndexMap = IndexMap::with_capacity(cap); + println!("wish: {}, got: {} (diff: {})", cap, map.capacity(), map.capacity() as isize - cap as isize); + map.capacity() >= cap + } + + fn drain_full(insert: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + let mut clone = map.clone(); + let drained = clone.drain(..); + for (key, _) in drained { + map.swap_remove(&key); + } + map.is_empty() + } + + fn drain_bounds(insert: Vec, range: (Bound, Bound)) -> TestResult { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + + // First see if `Vec::drain` is happy with this range. + let result = std::panic::catch_unwind(|| { + let mut keys: Vec = map.keys().copied().collect(); + keys.drain(range); + keys + }); + + if let Ok(keys) = result { + map.drain(range); + // Check that our `drain` matches the same key order. + assert!(map.keys().eq(&keys)); + // Check that hash lookups all work too. + assert!(keys.iter().all(|key| map.contains_key(key))); + TestResult::passed() + } else { + // If `Vec::drain` panicked, so should we. + TestResult::must_fail(move || { map.drain(range); }) + } + } + + fn shift_remove(insert: Vec, remove: Vec) -> bool { + let mut map = IndexMap::new(); + for &key in &insert { + map.insert(key, ()); + } + for &key in &remove { + map.shift_remove(&key); + } + let elements = &set(&insert) - &set(&remove); + + // Check that order is preserved after removals + let mut iter = map.keys(); + for &key in insert.iter().unique() { + if elements.contains(&key) { + assert_eq!(Some(&key), iter.next()); + } + } + + map.len() == elements.len() && map.iter().count() == elements.len() && + elements.iter().all(|k| map.get(k).is_some()) + } + + fn indexing(insert: Vec) -> bool { + let mut map: IndexMap<_, _> = insert.into_iter().map(|x| (x, x)).collect(); + let set: IndexSet<_> = map.keys().copied().collect(); + assert_eq!(map.len(), set.len()); + + for (i, &key) in set.iter().enumerate() { + assert_eq!(map.get_index(i), Some((&key, &key))); + assert_eq!(set.get_index(i), Some(&key)); + assert_eq!(map[i], key); + assert_eq!(set[i], key); + + *map.get_index_mut(i).unwrap().1 >>= 1; + map[i] <<= 1; + } + + set.iter().enumerate().all(|(i, &key)| { + let value = key & !1; + map[&key] == value && map[i] == value + }) + } +} + +use crate::Op::*; +#[derive(Copy, Clone, Debug)] +enum Op { + Add(K, V), + Remove(K), + AddEntry(K, V), + RemoveEntry(K), +} + +impl Arbitrary for Op +where + K: Arbitrary, + V: Arbitrary, +{ + fn arbitrary(g: &mut Gen) -> Self { + match u32::arbitrary(g) % 4 { + 0 => Add(K::arbitrary(g), V::arbitrary(g)), + 1 => AddEntry(K::arbitrary(g), V::arbitrary(g)), + 2 => Remove(K::arbitrary(g)), + _ => RemoveEntry(K::arbitrary(g)), + } + } +} + +fn do_ops(ops: &[Op], a: &mut IndexMap, b: &mut HashMap) +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher, +{ + for op in ops { + match *op { + Add(ref k, ref v) => { + a.insert(k.clone(), v.clone()); + b.insert(k.clone(), v.clone()); + } + AddEntry(ref k, ref v) => { + a.entry(k.clone()).or_insert_with(|| v.clone()); + b.entry(k.clone()).or_insert_with(|| v.clone()); + } + Remove(ref k) => { + a.swap_remove(k); + b.remove(k); + } + RemoveEntry(ref k) => { + if let OEntry::Occupied(ent) = a.entry(k.clone()) { + ent.swap_remove_entry(); + } + if let HEntry::Occupied(ent) = b.entry(k.clone()) { + ent.remove_entry(); + } + } + } + //println!("{:?}", a); + } +} + +fn assert_maps_equivalent(a: &IndexMap, b: &HashMap) -> bool +where + K: Hash + Eq + Debug, + V: Eq + Debug, +{ + assert_eq!(a.len(), b.len()); + assert_eq!(a.iter().next().is_some(), b.iter().next().is_some()); + for key in a.keys() { + assert!(b.contains_key(key), "b does not contain {:?}", key); + } + for key in b.keys() { + assert!(a.get(key).is_some(), "a does not contain {:?}", key); + } + for key in a.keys() { + assert_eq!(a[key], b[key]); + } + true +} + +quickcheck_limit! { + fn operations_i8(ops: Large>>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + assert_maps_equivalent(&map, &reference) + } + + fn operations_string(ops: Vec>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + assert_maps_equivalent(&map, &reference) + } + + fn keys_values(ops: Large>>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + let mut visit = IndexMap::new(); + for (k, v) in map.keys().zip(map.values()) { + assert_eq!(&map[k], v); + assert!(!visit.contains_key(k)); + visit.insert(*k, *v); + } + assert_eq!(visit.len(), reference.len()); + true + } + + fn keys_values_mut(ops: Large>>) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops, &mut map, &mut reference); + let mut visit = IndexMap::new(); + let keys = Vec::from_iter(map.keys().copied()); + for (k, v) in keys.iter().zip(map.values_mut()) { + assert_eq!(&reference[k], v); + assert!(!visit.contains_key(k)); + visit.insert(*k, *v); + } + assert_eq!(visit.len(), reference.len()); + true + } + + fn equality(ops1: Vec>, removes: Vec) -> bool { + let mut map = IndexMap::new(); + let mut reference = HashMap::new(); + do_ops(&ops1, &mut map, &mut reference); + let mut ops2 = ops1.clone(); + for &r in &removes { + if !ops2.is_empty() { + let i = r % ops2.len(); + ops2.remove(i); + } + } + let mut map2 = IndexMapFnv::default(); + let mut reference2 = HashMap::new(); + do_ops(&ops2, &mut map2, &mut reference2); + assert_eq!(map == map2, reference == reference2); + true + } + + fn retain_ordered(keys: Large>, remove: Large>) -> () { + let mut map = indexmap(keys.iter()); + let initial_map = map.clone(); // deduplicated in-order input + let remove_map = indexmap(remove.iter()); + let keys_s = set(keys.iter()); + let remove_s = set(remove.iter()); + let answer = &keys_s - &remove_s; + map.retain(|k, _| !remove_map.contains_key(k)); + + // check the values + assert_eq!(map.len(), answer.len()); + for key in &answer { + assert!(map.contains_key(key)); + } + // check the order + itertools::assert_equal(map.keys(), initial_map.keys().filter(|&k| !remove_map.contains_key(k))); + } + + fn sort_1(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + let mut answer = keyvals.0; + answer.sort_by_key(|t| t.0); + + // reverse dedup: Because IndexMap::from_iter keeps the last value for + // identical keys + answer.reverse(); + answer.dedup_by_key(|t| t.0); + answer.reverse(); + + map.sort_by(|k1, _, k2, _| Ord::cmp(k1, k2)); + + // check it contains all the values it should + for &(key, val) in &answer { + assert_eq!(map[&key], val); + } + + // check the order + + let mapv = Vec::from_iter(map); + assert_eq!(answer, mapv); + + } + + fn sort_2(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + map.sort_by(|_, v1, _, v2| Ord::cmp(v1, v2)); + assert_sorted_by_key(map, |t| t.1); + } + + fn reverse(keyvals: Large>) -> () { + let mut map: IndexMap<_, _> = IndexMap::from_iter(keyvals.to_vec()); + + fn generate_answer(input: &Vec<(i8, i8)>) -> Vec<(i8, i8)> { + // to mimic what `IndexMap::from_iter` does: + // need to get (A) the unique keys in forward order, and (B) the + // last value of each of those keys. + + // create (A): an iterable that yields the unique keys in ltr order + let mut seen_keys = HashSet::new(); + let unique_keys_forward = input.iter().filter_map(move |(k, _)| { + if seen_keys.contains(k) { None } + else { seen_keys.insert(*k); Some(*k) } + }); + + // create (B): a mapping of keys to the last value seen for that key + // this is the same as reversing the input and taking the first + // value seen for that key! + let mut last_val_per_key = HashMap::new(); + for &(k, v) in input.iter().rev() { + if !last_val_per_key.contains_key(&k) { + last_val_per_key.insert(k, v); + } + } + + // iterate over the keys in (A) in order, and match each one with + // the corresponding last value from (B) + let mut ans: Vec<_> = unique_keys_forward + .map(|k| (k, *last_val_per_key.get(&k).unwrap())) + .collect(); + + // finally, since this test is testing `.reverse()`, reverse the + // answer in-place + ans.reverse(); + + ans + } + + let answer = generate_answer(&keyvals.0); + + // perform the work + map.reverse(); + + // check it contains all the values it should + for &(key, val) in &answer { + assert_eq!(map[&key], val); + } + + // check the order + let mapv = Vec::from_iter(map); + assert_eq!(answer, mapv); + } +} + +fn assert_sorted_by_key(iterable: I, key: Key) +where + I: IntoIterator, + I::Item: Ord + Clone + Debug, + Key: Fn(&I::Item) -> X, + X: Ord, +{ + let input = Vec::from_iter(iterable); + let mut sorted = input.clone(); + sorted.sort_by_key(key); + assert_eq!(input, sorted); +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +struct Alpha(String); + +impl Deref for Alpha { + type Target = String; + fn deref(&self) -> &String { + &self.0 + } +} + +const ALPHABET: &[u8] = b"abcdefghijklmnopqrstuvwxyz"; + +impl Arbitrary for Alpha { + fn arbitrary(g: &mut Gen) -> Self { + let len = usize::arbitrary(g) % g.size(); + let len = min(len, 16); + Alpha( + (0..len) + .map(|_| ALPHABET[usize::arbitrary(g) % ALPHABET.len()] as char) + .collect(), + ) + } + + fn shrink(&self) -> Box> { + Box::new((**self).shrink().map(Alpha)) + } +} + +/// quickcheck Arbitrary adaptor -- make a larger vec +#[derive(Clone, Debug)] +struct Large(T); + +impl Deref for Large { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } +} + +impl Arbitrary for Large> +where + T: Arbitrary, +{ + fn arbitrary(g: &mut Gen) -> Self { + let len = usize::arbitrary(g) % (g.size() * 10); + Large((0..len).map(|_| T::arbitrary(g)).collect()) + } + + fn shrink(&self) -> Box> { + Box::new((**self).shrink().map(Large)) + } +} diff --git a/third_party/rust/indexmap/v1/crate/tests/tests.rs b/third_party/rust/indexmap/v1/crate/tests/tests.rs new file mode 100644 index 000000000000..7d522f1c9708 --- /dev/null +++ b/third_party/rust/indexmap/v1/crate/tests/tests.rs @@ -0,0 +1,28 @@ +use indexmap::{indexmap, indexset}; + +#[test] +fn test_sort() { + let m = indexmap! { + 1 => 2, + 7 => 1, + 2 => 2, + 3 => 3, + }; + + itertools::assert_equal( + m.sorted_by(|_k1, v1, _k2, v2| v1.cmp(v2)), + vec![(7, 1), (1, 2), (2, 2), (3, 3)], + ); +} + +#[test] +fn test_sort_set() { + let s = indexset! { + 1, + 7, + 2, + 3, + }; + + itertools::assert_equal(s.sorted_by(|v1, v2| v1.cmp(v2)), vec![1, 2, 3, 7]); +} diff --git a/third_party/rust/once_cell/v1/BUILD.gn b/third_party/rust/once_cell/v1/BUILD.gn new file mode 100644 index 000000000000..458b543e60b4 --- /dev/null +++ b/third_party/rust/once_cell/v1/BUILD.gn @@ -0,0 +1,59 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# @generated from third_party/rust/BUILD.gn.hbs by tools/crates/gnrt. +# Do not edit! + +import("//build/rust/cargo_crate.gni") + +cargo_crate("lib") { + crate_name = "once_cell" + epoch = "1" + crate_type = "rlib" + + # Only for usage from third-party crates. Add the crate to + # third_party.toml to use it from first-party code. + visibility = [ "//brave/third_party/rust/*" ] + crate_root = "crate/src/lib.rs" + sources = [ + "//brave/third_party/rust/once_cell/v1/crate/examples/bench.rs", + "//brave/third_party/rust/once_cell/v1/crate/examples/bench_acquire.rs", + "//brave/third_party/rust/once_cell/v1/crate/examples/bench_vs_lazy_static.rs", + "//brave/third_party/rust/once_cell/v1/crate/examples/lazy_static.rs", + "//brave/third_party/rust/once_cell/v1/crate/examples/reentrant_init_deadlocks.rs", + "//brave/third_party/rust/once_cell/v1/crate/examples/regex.rs", + "//brave/third_party/rust/once_cell/v1/crate/examples/test_synchronization.rs", + "//brave/third_party/rust/once_cell/v1/crate/src/imp_cs.rs", + "//brave/third_party/rust/once_cell/v1/crate/src/imp_pl.rs", + "//brave/third_party/rust/once_cell/v1/crate/src/imp_std.rs", + "//brave/third_party/rust/once_cell/v1/crate/src/lib.rs", + "//brave/third_party/rust/once_cell/v1/crate/src/race.rs", + "//brave/third_party/rust/once_cell/v1/crate/tests/it.rs", + ] + inputs = [ + "//brave/third_party/rust/once_cell/v1/crate/CHANGELOG.md", + "//brave/third_party/rust/once_cell/v1/crate/README.md", + ] + + # Unit tests skipped. Generate with --with-tests to include them. + build_native_rust_unit_tests = false + edition = "2021" + cargo_pkg_version = "1.16.0" + cargo_pkg_authors = "Aleksey Kladov " + cargo_pkg_name = "once_cell" + cargo_pkg_description = "Single assignment cells and lazy values." + library_configs -= [ "//build/config/compiler:chromium_code" ] + library_configs += [ "//build/config/compiler:no_chromium_code" ] + executable_configs -= [ "//build/config/compiler:chromium_code" ] + executable_configs += [ "//build/config/compiler:no_chromium_code" ] + features = [ + "alloc", + "race", + "std", + ] +} +group("test_support") { + public_deps = [ ":lib" ] + testonly = true +} diff --git a/third_party/rust/once_cell/v1/README.chromium b/third_party/rust/once_cell/v1/README.chromium new file mode 100644 index 000000000000..95ce029a013b --- /dev/null +++ b/third_party/rust/once_cell/v1/README.chromium @@ -0,0 +1,7 @@ +Name: once_cell +URL: https://crates.io/crates/once_cell +Description: Single assignment cells and lazy values. +Version: 1.16.0 +Security Critical: no +Shipped: no +License: Apache 2.0 diff --git a/third_party/rust/once_cell/v1/crate/.cargo_vcs_info.json b/third_party/rust/once_cell/v1/crate/.cargo_vcs_info.json new file mode 100644 index 000000000000..fabec9f09636 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "18e47d73088c0d60ec4a7da50b4ef50417bbc5df" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/rust/once_cell/v1/crate/.github/workflows/ci.yaml b/third_party/rust/once_cell/v1/crate/.github/workflows/ci.yaml new file mode 100644 index 000000000000..4aa9564eb639 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/.github/workflows/ci.yaml @@ -0,0 +1,28 @@ +name: CI +on: + pull_request: + push: + branches: ["master", "staging", "trying"] + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CI: 1 + RUST_BACKTRACE: short + RUSTFLAGS: -D warnings + RUSTUP_MAX_RETRIES: 10 + +jobs: + test: + name: Rust + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # fetch tags for publish + + - run: cargo run -p xtask -- ci + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} + MIRIFLAGS: -Zmiri-strict-provenance diff --git a/third_party/rust/once_cell/v1/crate/.gitignore b/third_party/rust/once_cell/v1/crate/.gitignore new file mode 100644 index 000000000000..ff0d8477be32 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/.gitignore @@ -0,0 +1,3 @@ +/target +/.vscode +Cargo.lock diff --git a/third_party/rust/once_cell/v1/crate/CHANGELOG.md b/third_party/rust/once_cell/v1/crate/CHANGELOG.md new file mode 100644 index 000000000000..5cf6ea6b768f --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/CHANGELOG.md @@ -0,0 +1,208 @@ +# Changelog + +## Unreleased + +- + +## 1.16.0 + +- Add `no_std` implementation based on `critical-section`, + [#195](https://github.com/matklad/once_cell/pull/195). +- Deprecate `atomic-polyfill` feature (use the new `critical-section` instead) + +## 1.15.0 + +- Increase minimal supported Rust version to 1.56.0. +- Implement `UnwindSafe` even if the `std` feature is disabled. + +## 1.14.0 + +- Add extension to `unsync` and `sync` `Lazy` mut API: + - `force_mut` + - `get_mut` + + +## 1.13.1 + +- Make implementation compliant with [strict provenance](https://github.com/rust-lang/rust/issues/95228). +- Upgrade `atomic-polyfill` to `1.0` + +## 1.13.0 + +- Add `Lazy::get`, similar to `OnceCell::get`. + +## 1.12.1 + +- Remove incorrect `debug_assert`. + +## 1.12.0 + +- Add `OnceCell::wait`, a blocking variant of `get`. + +## 1.11.0 + +- Add `OnceCell::with_value` to create initialized `OnceCell` in `const` context. +- Improve `Clone` implementation for `OnceCell`. +- Rewrite `parking_lot` version on top of `parking_lot_core`, for even smaller cells! + +## 1.10.0 + +- upgrade `parking_lot` to `0.12.0` (note that this bumps MSRV with `parking_lot` feature enabled to `1.49.0`). + +## 1.9.0 + +- Added an `atomic-polyfill` optional dependency to compile `race` on platforms without atomics + +## 1.8.0 + +- Add `try_insert` API -- a version of `set` that returns a reference. + +## 1.7.2 + +- Improve code size when using parking_lot feature. + +## 1.7.1 + +- Fix `race::OnceBox` to also impl `Default` even if `T` doesn't impl `Default`. + +## 1.7.0 + +- Hide the `race` module behind (default) `race` feature. + Turns out that adding `race` by default was a breaking change on some platforms without atomics. + In this release, we make the module opt-out. + Technically, this is a breaking change for those who use `race` with `no_default_features`. + Given that the `race` module itself only several days old, the breakage is deemed acceptable. + +## 1.6.0 + +- Add `Lazy::into_value` +- Stabilize `once_cell::race` module for "first one wins" no_std-compatible initialization flavor. +- Migrate from deprecated `compare_and_swap` to `compare_exchange`. + +## 1.5.2 + +- `OnceBox` API uses `Box`. + This a breaking change to unstable API. + +## 1.5.1 + +- MSRV is increased to `1.36.0`. +- document `once_cell::race` module. +- introduce `alloc` feature for `OnceBox`. +- fix `OnceBox::set`. + +## 1.5.0 + +- add new `once_cell::race` module for "first one wins" no_std-compatible initialization flavor. + The API is provisional, subject to change and is gated by the `unstable` cargo feature. + +## 1.4.1 + +- upgrade `parking_lot` to `0.11.0` +- make `sync::OnceCell` pass https://doc.rust-lang.org/nomicon/dropck.html#an-escape-hatch[dropck] with `parking_lot` feature enabled. + This fixes a (minor) semver-incompatible changed introduced in `1.4.0` + +## 1.4.0 + +- upgrade `parking_lot` to `0.10` (note that this bumps MSRV with `parking_lot` feature enabled to `1.36.0`). +- add `OnceCell::take`. +- upgrade crossbeam utils (private dependency) to `0.7`. + +## 1.3.1 + +- remove unnecessary `F: fmt::Debug` bound from `impl fmt::Debug for Lazy`. + +## 1.3.0 + +- `Lazy` now implements `DerefMut`. +- update implementation according to the latest changes in `std`. + +## 1.2.0 + +- add `sync::OnceCell::get_unchecked`. + +## 1.1.0 + +- implement `Default` for `Lazy`: it creates an empty `Lazy` which is initialized with `T::default` on first access. +- add `OnceCell::get_mut`. + +## 1.0.2 + +- actually add `#![no_std]` attribute if std feature is not enabled. + +## 1.0.1 + +- fix unsoundness in `Lazy` if the initializing function panics. Thanks [@xfix](https://github.com/xfix)! +- implement `RefUnwindSafe` for `Lazy`. +- share more code between `std` and `parking_lot` implementations. +- add F.A.Q section to the docs. + +## 1.0.0 + +- remove `parking_lot` from the list of default features. +- add `std` default feature. Without `std`, only `unsync` module is supported. +- implement `Eq` for `OnceCell`. +- fix wrong `Sync` bound on `sync::Lazy`. +- run the whole test suite with miri. + +## 0.2.7 + +- New implementation of `sync::OnceCell` if `parking_lot` feature is disabled. + It now employs a hand-rolled variant of `std::sync::Once`. +- `sync::OnceCell::get_or_try_init` works without `parking_lot` as well! +- document the effects of `parking_lot` feature: same performance but smaller types. + +## 0.2.6 + +- Updated `Lazy`'s `Deref` impl to requires only `FnOnce` instead of `Fn` + +## 0.2.5 + +- `Lazy` requires only `FnOnce` instead of `Fn` + +## 0.2.4 + +- nicer `fmt::Debug` implementation + +## 0.2.3 + +- update `parking_lot` to `0.9.0` +- fix stacked borrows violation in `unsync::OnceCell::get` +- implement `Clone` for `sync::OnceCell where T: Clone` + +## 0.2.2 + +- add `OnceCell::into_inner` which consumes a cell and returns an option + +## 0.2.1 + +- implement `sync::OnceCell::get_or_try_init` if `parking_lot` feature is enabled +- switch internal `unsafe` implementation of `sync::OnceCell` from `Once` to `Mutex` +- `sync::OnceCell::get_or_init` is twice as fast if cell is already initialized +- implement `std::panic::RefUnwindSafe` and `std::panic::UnwindSafe` for `OnceCell` +- better document behavior around panics + +## 0.2.0 + +- MSRV is now 1.31.1 +- `Lazy::new` and `OnceCell::new` are now const-fns +- `unsync_lazy` and `sync_lazy` macros are removed + +## 0.1.8 + +- update crossbeam-utils to 0.6 +- enable bors-ng + +## 0.1.7 + +- cells implement `PartialEq` and `From` +- MSRV is down to 1.24.1 +- update `parking_lot` to `0.7.1` + +## 0.1.6 + +- `unsync::OnceCell` is `Clone` if `T` is `Clone`. + +## 0.1.5 + +- No changelog until this point :( diff --git a/third_party/rust/once_cell/v1/crate/Cargo.toml b/third_party/rust/once_cell/v1/crate/Cargo.toml new file mode 100644 index 000000000000..6587f4e52e3e --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/Cargo.toml @@ -0,0 +1,109 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "once_cell" +version = "1.16.0" +authors = ["Aleksey Kladov "] +exclude = [ + "*.png", + "*.svg", + "/Cargo.lock.msrv", + "rustfmt.toml", +] +description = "Single assignment cells and lazy values." +documentation = "https://docs.rs/once_cell" +readme = "README.md" +keywords = [ + "lazy", + "static", +] +categories = [ + "rust-patterns", + "memory-management", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/matklad/once_cell" + +[package.metadata.docs.rs] +all-features = true + +[[example]] +name = "bench" +required-features = ["std"] + +[[example]] +name = "bench_acquire" +required-features = ["std"] + +[[example]] +name = "bench_vs_lazy_static" +required-features = ["std"] + +[[example]] +name = "lazy_static" +required-features = ["std"] + +[[example]] +name = "reentrant_init_deadlocks" +required-features = ["std"] + +[[example]] +name = "regex" +required-features = ["std"] + +[[example]] +name = "test_synchronization" +required-features = ["std"] + +[dependencies.atomic_polyfill] +version = "1" +optional = true +package = "atomic-polyfill" + +[dependencies.critical_section] +version = "1" +optional = true +package = "critical-section" + +[dependencies.parking_lot_core] +version = "0.9.3" +optional = true +default_features = false + +[dev-dependencies.critical_section] +version = "1.1.1" +features = ["std"] +package = "critical-section" + +[dev-dependencies.crossbeam-utils] +version = "0.8.7" + +[dev-dependencies.lazy_static] +version = "1.0.0" + +[dev-dependencies.regex] +version = "1.2.0" + +[features] +alloc = ["race"] +atomic-polyfill = ["critical-section"] +critical-section = [ + "critical_section", + "atomic_polyfill", +] +default = ["std"] +parking_lot = ["parking_lot_core"] +race = [] +std = ["alloc"] +unstable = [] diff --git a/third_party/rust/once_cell/v1/crate/Cargo.toml.orig b/third_party/rust/once_cell/v1/crate/Cargo.toml.orig new file mode 100644 index 000000000000..9a9a6df0b24d --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/Cargo.toml.orig @@ -0,0 +1,93 @@ +[package] +name = "once_cell" +version = "1.16.0" +authors = ["Aleksey Kladov "] +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.56" + +description = "Single assignment cells and lazy values." +readme = "README.md" +documentation = "https://docs.rs/once_cell" + +repository = "https://github.com/matklad/once_cell" +keywords = ["lazy", "static"] +categories = ["rust-patterns", "memory-management"] + +exclude = ["*.png", "*.svg", "/Cargo.lock.msrv", "rustfmt.toml"] + +[workspace] +members = ["xtask"] + +[dependencies] +# These optional dependencies are considered private impl details, +# only features from `[features]` table are a part of semver-guarded API. +parking_lot_core = { version = "0.9.3", optional = true, default_features = false } +atomic_polyfill = { package = "atomic-polyfill", version = "1", optional = true } +critical_section = { package = "critical-section", version = "1", optional = true } + +[dev-dependencies] +lazy_static = "1.0.0" +crossbeam-utils = "0.8.7" +regex = "1.2.0" +critical_section = { package = "critical-section", version = "1.1.1", features = ["std"] } + +[features] +default = ["std"] + +# Enables `once_cell::sync` module. +std = ["alloc"] + +# Enables `once_cell::race::OnceBox` type. +alloc = ["race"] + +# Enables `once_cell::race` module. +race = [] + +# Uses parking_lot to implement once_cell::sync::OnceCell. +# This makes no speed difference, but makes each OnceCell +# up to 16 bytes smaller, depending on the size of the T. +parking_lot = ["parking_lot_core"] + +# Uses `critical-section` to implement `sync` and `race` modules. in +# `#![no_std]` mode. Please read `critical-section` docs carefully +# before enabling this feature. +critical-section = ["critical_section", "atomic_polyfill" ] + +# Enables semver-exempt APIs of this crate. +# At the moment, this feature is unused. +unstable = [] + +# Only for backwards compatibility. +atomic-polyfill = ["critical-section"] + +[[example]] +name = "bench" +required-features = ["std"] + +[[example]] +name = "bench_acquire" +required-features = ["std"] + +[[example]] +name = "bench_vs_lazy_static" +required-features = ["std"] + +[[example]] +name = "lazy_static" +required-features = ["std"] + +[[example]] +name = "reentrant_init_deadlocks" +required-features = ["std"] + +[[example]] +name = "regex" +required-features = ["std"] + +[[example]] +name = "test_synchronization" +required-features = ["std"] + +[package.metadata.docs.rs] +all-features = true diff --git a/third_party/rust/once_cell/v1/crate/LICENSE-APACHE b/third_party/rust/once_cell/v1/crate/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/once_cell/v1/crate/LICENSE-MIT b/third_party/rust/once_cell/v1/crate/LICENSE-MIT new file mode 100644 index 000000000000..31aa79387f27 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/once_cell/v1/crate/README.md b/third_party/rust/once_cell/v1/crate/README.md new file mode 100644 index 000000000000..de65dbbcc1b7 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/README.md @@ -0,0 +1,56 @@ +

once_cell

+ + +[![Build Status](https://github.com/matklad/once_cell/actions/workflows/ci.yaml/badge.svg)](https://github.com/matklad/once_cell/actions) +[![Crates.io](https://img.shields.io/crates/v/once_cell.svg)](https://crates.io/crates/once_cell) +[![API reference](https://docs.rs/once_cell/badge.svg)](https://docs.rs/once_cell/) + +# Overview + +`once_cell` provides two new cell-like types, `unsync::OnceCell` and `sync::OnceCell`. `OnceCell` +might store arbitrary non-`Copy` types, can be assigned to at most once and provide direct access +to the stored contents. In a nutshell, API looks *roughly* like this: + +```rust +impl OnceCell { + fn new() -> OnceCell { ... } + fn set(&self, value: T) -> Result<(), T> { ... } + fn get(&self) -> Option<&T> { ... } +} +``` + +Note that, like with `RefCell` and `Mutex`, the `set` method requires only a shared reference. +Because of the single assignment restriction `get` can return an `&T` instead of `Ref` +or `MutexGuard`. + +`once_cell` also has a `Lazy` type, build on top of `OnceCell` which provides the same API as +the `lazy_static!` macro, but without using any macros: + +```rust +use std::{sync::Mutex, collections::HashMap}; +use once_cell::sync::Lazy; + +static GLOBAL_DATA: Lazy>> = Lazy::new(|| { + let mut m = HashMap::new(); + m.insert(13, "Spica".to_string()); + m.insert(74, "Hoyten".to_string()); + Mutex::new(m) +}); + +fn main() { + println!("{:?}", GLOBAL_DATA.lock().unwrap()); +} +``` + +More patterns and use-cases are in the [docs](https://docs.rs/once_cell/)! + +# Related crates + +* [double-checked-cell](https://github.com/niklasf/double-checked-cell) +* [lazy-init](https://crates.io/crates/lazy-init) +* [lazycell](https://crates.io/crates/lazycell) +* [mitochondria](https://crates.io/crates/mitochondria) +* [lazy_static](https://crates.io/crates/lazy_static) + +The API of `once_cell` is being proposed for inclusion in +[`std`](https://github.com/rust-lang/rfcs/pull/2788). diff --git a/third_party/rust/once_cell/v1/crate/bors.toml b/third_party/rust/once_cell/v1/crate/bors.toml new file mode 100644 index 000000000000..b92b99ac3020 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/bors.toml @@ -0,0 +1,2 @@ +status = [ "Rust" ] +delete_merged_branches = true diff --git a/third_party/rust/once_cell/v1/crate/examples/bench.rs b/third_party/rust/once_cell/v1/crate/examples/bench.rs new file mode 100644 index 000000000000..e6801258a1e6 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/examples/bench.rs @@ -0,0 +1,28 @@ +use std::mem::size_of; + +use once_cell::sync::OnceCell; + +const N_THREADS: usize = 32; +const N_ROUNDS: usize = 100_000_000; + +static CELL: OnceCell = OnceCell::new(); + +fn main() { + let start = std::time::Instant::now(); + let threads = + (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); + for thread in threads { + thread.join().unwrap(); + } + println!("{:?}", start.elapsed()); + println!("size_of::>() = {:?}", size_of::>()); + println!("size_of::>() = {:?}", size_of::>()); + println!("size_of::>() = {:?}", size_of::>()); +} + +fn thread_main(i: usize) { + for _ in 0..N_ROUNDS { + let &value = CELL.get_or_init(|| i); + assert!(value < N_THREADS) + } +} diff --git a/third_party/rust/once_cell/v1/crate/examples/bench_acquire.rs b/third_party/rust/once_cell/v1/crate/examples/bench_acquire.rs new file mode 100644 index 000000000000..151804746047 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/examples/bench_acquire.rs @@ -0,0 +1,39 @@ +//! Benchmark the overhead that the synchronization of `OnceCell::get` causes. +//! We do some other operations that write to memory to get an imprecise but somewhat realistic +//! measurement. + +use once_cell::sync::OnceCell; +use std::sync::atomic::{AtomicUsize, Ordering}; + +const N_THREADS: usize = 16; +const N_ROUNDS: usize = 1_000_000; + +static CELL: OnceCell = OnceCell::new(); +static OTHER: AtomicUsize = AtomicUsize::new(0); + +fn main() { + let start = std::time::Instant::now(); + let threads = + (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); + for thread in threads { + thread.join().unwrap(); + } + println!("{:?}", start.elapsed()); + println!("{:?}", OTHER.load(Ordering::Relaxed)); +} + +#[inline(never)] +fn thread_main(i: usize) { + // The operations we do here don't really matter, as long as we do multiple writes, and + // everything is messy enough to prevent the compiler from optimizing the loop away. + let mut data = [i; 128]; + let mut accum = 0usize; + for _ in 0..N_ROUNDS { + let _value = CELL.get_or_init(|| i + 1); + let k = OTHER.fetch_add(data[accum & 0x7F] as usize, Ordering::Relaxed); + for j in data.iter_mut() { + *j = (*j).wrapping_add(accum); + accum = accum.wrapping_add(k); + } + } +} diff --git a/third_party/rust/once_cell/v1/crate/examples/bench_vs_lazy_static.rs b/third_party/rust/once_cell/v1/crate/examples/bench_vs_lazy_static.rs new file mode 100644 index 000000000000..c23b0124e456 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/examples/bench_vs_lazy_static.rs @@ -0,0 +1,51 @@ +use lazy_static::lazy_static; +use once_cell::sync::Lazy; + +const N_THREADS: usize = 32; +const N_ROUNDS: usize = 100_000_000; + +static ONCE_CELL: Lazy> = Lazy::new(|| vec!["Spica".to_string(), "Hoyten".to_string()]); + +lazy_static! { + static ref LAZY_STATIC: Vec = vec!["Spica".to_string(), "Hoyten".to_string()]; +} + +fn main() { + let once_cell = { + let start = std::time::Instant::now(); + let threads = (0..N_THREADS) + .map(|_| std::thread::spawn(move || thread_once_cell())) + .collect::>(); + for thread in threads { + thread.join().unwrap(); + } + start.elapsed() + }; + let lazy_static = { + let start = std::time::Instant::now(); + let threads = (0..N_THREADS) + .map(|_| std::thread::spawn(move || thread_lazy_static())) + .collect::>(); + for thread in threads { + thread.join().unwrap(); + } + start.elapsed() + }; + + println!("once_cell: {:?}", once_cell); + println!("lazy_static: {:?}", lazy_static); +} + +fn thread_once_cell() { + for _ in 0..N_ROUNDS { + let len = ONCE_CELL.len(); + assert_eq!(len, 2) + } +} + +fn thread_lazy_static() { + for _ in 0..N_ROUNDS { + let len = LAZY_STATIC.len(); + assert_eq!(len, 2) + } +} diff --git a/third_party/rust/once_cell/v1/crate/examples/lazy_static.rs b/third_party/rust/once_cell/v1/crate/examples/lazy_static.rs new file mode 100644 index 000000000000..3cdb19f2a5d3 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/examples/lazy_static.rs @@ -0,0 +1,36 @@ +extern crate once_cell; + +use once_cell::sync::{Lazy, OnceCell}; +use std::collections::HashMap; + +static HASHMAP: Lazy> = Lazy::new(|| { + let mut m = HashMap::new(); + m.insert(0, "foo"); + m.insert(1, "bar"); + m.insert(2, "baz"); + m +}); + +// Same, but completely without macros +fn hashmap() -> &'static HashMap { + static INSTANCE: OnceCell> = OnceCell::new(); + INSTANCE.get_or_init(|| { + let mut m = HashMap::new(); + m.insert(0, "foo"); + m.insert(1, "bar"); + m.insert(2, "baz"); + m + }) +} + +fn main() { + // First access to `HASHMAP` initializes it + println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); + + // Any further access to `HASHMAP` just returns the computed value + println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap()); + + // The same works for function-style: + assert_eq!(hashmap().get(&0), Some(&"foo")); + assert_eq!(hashmap().get(&1), Some(&"bar")); +} diff --git a/third_party/rust/once_cell/v1/crate/examples/reentrant_init_deadlocks.rs b/third_party/rust/once_cell/v1/crate/examples/reentrant_init_deadlocks.rs new file mode 100644 index 000000000000..af4b5b7d0e79 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/examples/reentrant_init_deadlocks.rs @@ -0,0 +1,14 @@ +fn main() { + let cell = once_cell::sync::OnceCell::::new(); + cell.get_or_init(|| { + cell.get_or_init(|| 1); + 2 + }); +} + +/// Dummy test to make it seem hang when compiled as `--test` +/// See https://github.com/matklad/once_cell/issues/79 +#[test] +fn dummy_test() { + std::thread::sleep(std::time::Duration::from_secs(4)); +} diff --git a/third_party/rust/once_cell/v1/crate/examples/regex.rs b/third_party/rust/once_cell/v1/crate/examples/regex.rs new file mode 100644 index 000000000000..4c4c2ea6b8ab --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/examples/regex.rs @@ -0,0 +1,49 @@ +use std::{str::FromStr, time::Instant}; + +use regex::Regex; + +macro_rules! regex { + ($re:literal $(,)?) => {{ + static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); + RE.get_or_init(|| regex::Regex::new($re).unwrap()) + }}; +} + +fn slow() { + let s = r##"13.28.24.13 - - [10/Mar/2016:19:29:25 +0100] "GET /etc/lib/pChart2/examples/index.php?Action=View&Script=../../../../cnf/db.php HTTP/1.1" 404 151 "-" "HTTP_Request2/2.2.1 (http://pear.php.net/package/http_request2) PHP/5.3.16""##; + + let mut total = 0; + for _ in 0..1000 { + let re = Regex::new( + r##"^(\S+) (\S+) (\S+) \[([^]]+)\] "([^"]*)" (\d+) (\d+) "([^"]*)" "([^"]*)"$"##, + ) + .unwrap(); + let size = usize::from_str(re.captures(s).unwrap().get(7).unwrap().as_str()).unwrap(); + total += size; + } + println!("{}", total); +} + +fn fast() { + let s = r##"13.28.24.13 - - [10/Mar/2016:19:29:25 +0100] "GET /etc/lib/pChart2/examples/index.php?Action=View&Script=../../../../cnf/db.php HTTP/1.1" 404 151 "-" "HTTP_Request2/2.2.1 (http://pear.php.net/package/http_request2) PHP/5.3.16""##; + + let mut total = 0; + for _ in 0..1000 { + let re: &Regex = regex!( + r##"^(\S+) (\S+) (\S+) \[([^]]+)\] "([^"]*)" (\d+) (\d+) "([^"]*)" "([^"]*)"$"##, + ); + let size = usize::from_str(re.captures(s).unwrap().get(7).unwrap().as_str()).unwrap(); + total += size; + } + println!("{}", total); +} + +fn main() { + let t = Instant::now(); + slow(); + println!("slow: {:?}", t.elapsed()); + + let t = Instant::now(); + fast(); + println!("fast: {:?}", t.elapsed()); +} diff --git a/third_party/rust/once_cell/v1/crate/examples/test_synchronization.rs b/third_party/rust/once_cell/v1/crate/examples/test_synchronization.rs new file mode 100644 index 000000000000..0d54f9827ea3 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/examples/test_synchronization.rs @@ -0,0 +1,38 @@ +//! Test if the OnceCell properly synchronizes. +//! Needs to be run in release mode. +//! +//! We create a `Vec` with `N_ROUNDS` of `OnceCell`s. All threads will walk the `Vec`, and race to +//! be the first one to initialize a cell. +//! Every thread adds the results of the cells it sees to an accumulator, which is compared at the +//! end. +//! All threads should end up with the same result. + +use once_cell::sync::OnceCell; + +const N_THREADS: usize = 32; +const N_ROUNDS: usize = 1_000_000; + +static CELLS: OnceCell>> = OnceCell::new(); +static RESULT: OnceCell = OnceCell::new(); + +fn main() { + let start = std::time::Instant::now(); + CELLS.get_or_init(|| vec![OnceCell::new(); N_ROUNDS]); + let threads = + (0..N_THREADS).map(|i| std::thread::spawn(move || thread_main(i))).collect::>(); + for thread in threads { + thread.join().unwrap(); + } + println!("{:?}", start.elapsed()); + println!("No races detected"); +} + +fn thread_main(i: usize) { + let cells = CELLS.get().unwrap(); + let mut accum = 0; + for cell in cells.iter() { + let &value = cell.get_or_init(|| i); + accum += value; + } + assert_eq!(RESULT.get_or_init(|| accum), &accum); +} diff --git a/third_party/rust/once_cell/v1/crate/src/imp_cs.rs b/third_party/rust/once_cell/v1/crate/src/imp_cs.rs new file mode 100644 index 000000000000..668f18ec634d --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/src/imp_cs.rs @@ -0,0 +1,78 @@ +use core::panic::{RefUnwindSafe, UnwindSafe}; + +use atomic_polyfill::{AtomicBool, Ordering}; +use critical_section::{CriticalSection, Mutex}; + +use crate::unsync; + +pub(crate) struct OnceCell { + initialized: AtomicBool, + // Use `unsync::OnceCell` internally since `Mutex` does not provide + // interior mutability and to be able to re-use `get_or_try_init`. + value: Mutex>, +} + +// Why do we need `T: Send`? +// Thread A creates a `OnceCell` and shares it with +// scoped thread B, which fills the cell, which is +// then destroyed by A. That is, destructor observes +// a sent value. +unsafe impl Sync for OnceCell {} +unsafe impl Send for OnceCell {} + +impl RefUnwindSafe for OnceCell {} +impl UnwindSafe for OnceCell {} + +impl OnceCell { + pub(crate) const fn new() -> OnceCell { + OnceCell { initialized: AtomicBool::new(false), value: Mutex::new(unsync::OnceCell::new()) } + } + + pub(crate) const fn with_value(value: T) -> OnceCell { + OnceCell { + initialized: AtomicBool::new(true), + value: Mutex::new(unsync::OnceCell::with_value(value)), + } + } + + #[inline] + pub(crate) fn is_initialized(&self) -> bool { + self.initialized.load(Ordering::Acquire) + } + + #[cold] + pub(crate) fn initialize(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result, + { + critical_section::with(|cs| { + let cell = self.value.borrow(cs); + cell.get_or_try_init(f).map(|_| { + self.initialized.store(true, Ordering::Release); + }) + }) + } + + /// Get the reference to the underlying value, without checking if the cell + /// is initialized. + /// + /// # Safety + /// + /// Caller must ensure that the cell is in initialized state, and that + /// the contents are acquired by (synchronized to) this thread. + pub(crate) unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + // SAFETY: The caller ensures that the value is initialized and access synchronized. + crate::unwrap_unchecked(self.value.borrow(CriticalSection::new()).get()) + } + + #[inline] + pub(crate) fn get_mut(&mut self) -> Option<&mut T> { + self.value.get_mut().get_mut() + } + + #[inline] + pub(crate) fn into_inner(self) -> Option { + self.value.into_inner().into_inner() + } +} diff --git a/third_party/rust/once_cell/v1/crate/src/imp_pl.rs b/third_party/rust/once_cell/v1/crate/src/imp_pl.rs new file mode 100644 index 000000000000..84d8593863b7 --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/src/imp_pl.rs @@ -0,0 +1,174 @@ +use std::{ + cell::UnsafeCell, + panic::{RefUnwindSafe, UnwindSafe}, + sync::atomic::{AtomicU8, Ordering}, +}; + +pub(crate) struct OnceCell { + state: AtomicU8, + value: UnsafeCell>, +} + +const INCOMPLETE: u8 = 0x0; +const RUNNING: u8 = 0x1; +const COMPLETE: u8 = 0x2; + +// Why do we need `T: Send`? +// Thread A creates a `OnceCell` and shares it with +// scoped thread B, which fills the cell, which is +// then destroyed by A. That is, destructor observes +// a sent value. +unsafe impl Sync for OnceCell {} +unsafe impl Send for OnceCell {} + +impl RefUnwindSafe for OnceCell {} +impl UnwindSafe for OnceCell {} + +impl OnceCell { + pub(crate) const fn new() -> OnceCell { + OnceCell { state: AtomicU8::new(INCOMPLETE), value: UnsafeCell::new(None) } + } + + pub(crate) const fn with_value(value: T) -> OnceCell { + OnceCell { state: AtomicU8::new(COMPLETE), value: UnsafeCell::new(Some(value)) } + } + + /// Safety: synchronizes with store to value via Release/Acquire. + #[inline] + pub(crate) fn is_initialized(&self) -> bool { + self.state.load(Ordering::Acquire) == COMPLETE + } + + /// Safety: synchronizes with store to value via `is_initialized` or mutex + /// lock/unlock, writes value only once because of the mutex. + #[cold] + pub(crate) fn initialize(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result, + { + let mut f = Some(f); + let mut res: Result<(), E> = Ok(()); + let slot: *mut Option = self.value.get(); + initialize_inner(&self.state, &mut || { + // We are calling user-supplied function and need to be careful. + // - if it returns Err, we unlock mutex and return without touching anything + // - if it panics, we unlock mutex and propagate panic without touching anything + // - if it calls `set` or `get_or_try_init` re-entrantly, we get a deadlock on + // mutex, which is important for safety. We *could* detect this and panic, + // but that is more complicated + // - finally, if it returns Ok, we store the value and store the flag with + // `Release`, which synchronizes with `Acquire`s. + let f = unsafe { crate::unwrap_unchecked(f.take()) }; + match f() { + Ok(value) => unsafe { + // Safe b/c we have a unique access and no panic may happen + // until the cell is marked as initialized. + debug_assert!((*slot).is_none()); + *slot = Some(value); + true + }, + Err(err) => { + res = Err(err); + false + } + } + }); + res + } + + #[cold] + pub(crate) fn wait(&self) { + let key = &self.state as *const _ as usize; + unsafe { + parking_lot_core::park( + key, + || self.state.load(Ordering::Acquire) != COMPLETE, + || (), + |_, _| (), + parking_lot_core::DEFAULT_PARK_TOKEN, + None, + ); + } + } + + /// Get the reference to the underlying value, without checking if the cell + /// is initialized. + /// + /// # Safety + /// + /// Caller must ensure that the cell is in initialized state, and that + /// the contents are acquired by (synchronized to) this thread. + pub(crate) unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + let slot = &*self.value.get(); + crate::unwrap_unchecked(slot.as_ref()) + } + + /// Gets the mutable reference to the underlying value. + /// Returns `None` if the cell is empty. + pub(crate) fn get_mut(&mut self) -> Option<&mut T> { + // Safe b/c we have an exclusive access + let slot: &mut Option = unsafe { &mut *self.value.get() }; + slot.as_mut() + } + + /// Consumes this `OnceCell`, returning the wrapped value. + /// Returns `None` if the cell was empty. + pub(crate) fn into_inner(self) -> Option { + self.value.into_inner() + } +} + +struct Guard<'a> { + state: &'a AtomicU8, + new_state: u8, +} + +impl<'a> Drop for Guard<'a> { + fn drop(&mut self) { + self.state.store(self.new_state, Ordering::Release); + unsafe { + let key = self.state as *const AtomicU8 as usize; + parking_lot_core::unpark_all(key, parking_lot_core::DEFAULT_UNPARK_TOKEN); + } + } +} + +// Note: this is intentionally monomorphic +#[inline(never)] +fn initialize_inner(state: &AtomicU8, init: &mut dyn FnMut() -> bool) { + loop { + let exchange = + state.compare_exchange_weak(INCOMPLETE, RUNNING, Ordering::Acquire, Ordering::Acquire); + match exchange { + Ok(_) => { + let mut guard = Guard { state, new_state: INCOMPLETE }; + if init() { + guard.new_state = COMPLETE; + } + return; + } + Err(COMPLETE) => return, + Err(RUNNING) => unsafe { + let key = state as *const AtomicU8 as usize; + parking_lot_core::park( + key, + || state.load(Ordering::Relaxed) == RUNNING, + || (), + |_, _| (), + parking_lot_core::DEFAULT_PARK_TOKEN, + None, + ); + }, + Err(INCOMPLETE) => (), + Err(_) => debug_assert!(false), + } + } +} + +#[test] +fn test_size() { + use std::mem::size_of; + + assert_eq!(size_of::>(), 1 * size_of::() + size_of::()); +} diff --git a/third_party/rust/once_cell/v1/crate/src/imp_std.rs b/third_party/rust/once_cell/v1/crate/src/imp_std.rs new file mode 100644 index 000000000000..5761f0184b9c --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/src/imp_std.rs @@ -0,0 +1,425 @@ +// There's a lot of scary concurrent code in this module, but it is copied from +// `std::sync::Once` with two changes: +// * no poisoning +// * init function can fail + +use std::{ + cell::{Cell, UnsafeCell}, + marker::PhantomData, + panic::{RefUnwindSafe, UnwindSafe}, + sync::atomic::{AtomicBool, AtomicPtr, Ordering}, + thread::{self, Thread}, +}; + +#[derive(Debug)] +pub(crate) struct OnceCell { + // This `queue` field is the core of the implementation. It encodes two + // pieces of information: + // + // * The current state of the cell (`INCOMPLETE`, `RUNNING`, `COMPLETE`) + // * Linked list of threads waiting for the current cell. + // + // State is encoded in two low bits. Only `INCOMPLETE` and `RUNNING` states + // allow waiters. + queue: AtomicPtr, + _marker: PhantomData<*mut Waiter>, + value: UnsafeCell>, +} + +// Why do we need `T: Send`? +// Thread A creates a `OnceCell` and shares it with +// scoped thread B, which fills the cell, which is +// then destroyed by A. That is, destructor observes +// a sent value. +unsafe impl Sync for OnceCell {} +unsafe impl Send for OnceCell {} + +impl RefUnwindSafe for OnceCell {} +impl UnwindSafe for OnceCell {} + +impl OnceCell { + pub(crate) const fn new() -> OnceCell { + OnceCell { + queue: AtomicPtr::new(INCOMPLETE_PTR), + _marker: PhantomData, + value: UnsafeCell::new(None), + } + } + + pub(crate) const fn with_value(value: T) -> OnceCell { + OnceCell { + queue: AtomicPtr::new(COMPLETE_PTR), + _marker: PhantomData, + value: UnsafeCell::new(Some(value)), + } + } + + /// Safety: synchronizes with store to value via Release/(Acquire|SeqCst). + #[inline] + pub(crate) fn is_initialized(&self) -> bool { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us, and, this being a fast path, weaker + // ordering helps with performance. This `Acquire` synchronizes with + // `SeqCst` operations on the slow path. + self.queue.load(Ordering::Acquire) == COMPLETE_PTR + } + + /// Safety: synchronizes with store to value via SeqCst read from state, + /// writes value only once because we never get to INCOMPLETE state after a + /// successful write. + #[cold] + pub(crate) fn initialize(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result, + { + let mut f = Some(f); + let mut res: Result<(), E> = Ok(()); + let slot: *mut Option = self.value.get(); + initialize_or_wait( + &self.queue, + Some(&mut || { + let f = unsafe { crate::unwrap_unchecked(f.take()) }; + match f() { + Ok(value) => { + unsafe { *slot = Some(value) }; + true + } + Err(err) => { + res = Err(err); + false + } + } + }), + ); + res + } + + #[cold] + pub(crate) fn wait(&self) { + initialize_or_wait(&self.queue, None); + } + + /// Get the reference to the underlying value, without checking if the cell + /// is initialized. + /// + /// # Safety + /// + /// Caller must ensure that the cell is in initialized state, and that + /// the contents are acquired by (synchronized to) this thread. + pub(crate) unsafe fn get_unchecked(&self) -> &T { + debug_assert!(self.is_initialized()); + let slot = &*self.value.get(); + crate::unwrap_unchecked(slot.as_ref()) + } + + /// Gets the mutable reference to the underlying value. + /// Returns `None` if the cell is empty. + pub(crate) fn get_mut(&mut self) -> Option<&mut T> { + // Safe b/c we have a unique access. + unsafe { &mut *self.value.get() }.as_mut() + } + + /// Consumes this `OnceCell`, returning the wrapped value. + /// Returns `None` if the cell was empty. + #[inline] + pub(crate) fn into_inner(self) -> Option { + // Because `into_inner` takes `self` by value, the compiler statically + // verifies that it is not currently borrowed. + // So, it is safe to move out `Option`. + self.value.into_inner() + } +} + +// Three states that a OnceCell can be in, encoded into the lower bits of `queue` in +// the OnceCell structure. +const INCOMPLETE: usize = 0x0; +const RUNNING: usize = 0x1; +const COMPLETE: usize = 0x2; +const INCOMPLETE_PTR: *mut Waiter = INCOMPLETE as *mut Waiter; +const COMPLETE_PTR: *mut Waiter = COMPLETE as *mut Waiter; + +// Mask to learn about the state. All other bits are the queue of waiters if +// this is in the RUNNING state. +const STATE_MASK: usize = 0x3; + +/// Representation of a node in the linked list of waiters in the RUNNING state. +/// A waiters is stored on the stack of the waiting threads. +#[repr(align(4))] // Ensure the two lower bits are free to use as state bits. +struct Waiter { + thread: Cell>, + signaled: AtomicBool, + next: *mut Waiter, +} + +/// Drains and notifies the queue of waiters on drop. +struct Guard<'a> { + queue: &'a AtomicPtr, + new_queue: *mut Waiter, +} + +impl Drop for Guard<'_> { + fn drop(&mut self) { + let queue = self.queue.swap(self.new_queue, Ordering::AcqRel); + + let state = strict::addr(queue) & STATE_MASK; + assert_eq!(state, RUNNING); + + unsafe { + let mut waiter = strict::map_addr(queue, |q| q & !STATE_MASK); + while !waiter.is_null() { + let next = (*waiter).next; + let thread = (*waiter).thread.take().unwrap(); + (*waiter).signaled.store(true, Ordering::Release); + waiter = next; + thread.unpark(); + } + } + } +} + +// Corresponds to `std::sync::Once::call_inner`. +// +// Originally copied from std, but since modified to remove poisoning and to +// support wait. +// +// Note: this is intentionally monomorphic +#[inline(never)] +fn initialize_or_wait(queue: &AtomicPtr, mut init: Option<&mut dyn FnMut() -> bool>) { + let mut curr_queue = queue.load(Ordering::Acquire); + + loop { + let curr_state = strict::addr(curr_queue) & STATE_MASK; + match (curr_state, &mut init) { + (COMPLETE, _) => return, + (INCOMPLETE, Some(init)) => { + let exchange = queue.compare_exchange( + curr_queue, + strict::map_addr(curr_queue, |q| (q & !STATE_MASK) | RUNNING), + Ordering::Acquire, + Ordering::Acquire, + ); + if let Err(new_queue) = exchange { + curr_queue = new_queue; + continue; + } + let mut guard = Guard { queue, new_queue: INCOMPLETE_PTR }; + if init() { + guard.new_queue = COMPLETE_PTR; + } + return; + } + (INCOMPLETE, None) | (RUNNING, _) => { + wait(&queue, curr_queue); + curr_queue = queue.load(Ordering::Acquire); + } + _ => debug_assert!(false), + } + } +} + +fn wait(queue: &AtomicPtr, mut curr_queue: *mut Waiter) { + let curr_state = strict::addr(curr_queue) & STATE_MASK; + loop { + let node = Waiter { + thread: Cell::new(Some(thread::current())), + signaled: AtomicBool::new(false), + next: strict::map_addr(curr_queue, |q| q & !STATE_MASK), + }; + let me = &node as *const Waiter as *mut Waiter; + + let exchange = queue.compare_exchange( + curr_queue, + strict::map_addr(me, |q| q | curr_state), + Ordering::Release, + Ordering::Relaxed, + ); + if let Err(new_queue) = exchange { + if strict::addr(new_queue) & STATE_MASK != curr_state { + return; + } + curr_queue = new_queue; + continue; + } + + while !node.signaled.load(Ordering::Acquire) { + thread::park(); + } + break; + } +} + +// Polyfill of strict provenance from https://crates.io/crates/sptr. +// +// Use free-standing function rather than a trait to keep things simple and +// avoid any potential conflicts with future stabile std API. +mod strict { + #[must_use] + #[inline] + pub(crate) fn addr(ptr: *mut T) -> usize + where + T: Sized, + { + // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. + // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the + // provenance). + unsafe { core::mem::transmute(ptr) } + } + + #[must_use] + #[inline] + pub(crate) fn with_addr(ptr: *mut T, addr: usize) -> *mut T + where + T: Sized, + { + // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. + // + // In the mean-time, this operation is defined to be "as if" it was + // a wrapping_offset, so we can emulate it as such. This should properly + // restore pointer provenance even under today's compiler. + let self_addr = self::addr(ptr) as isize; + let dest_addr = addr as isize; + let offset = dest_addr.wrapping_sub(self_addr); + + // This is the canonical desugarring of this operation, + // but `pointer::cast` was only stabilized in 1.38. + // self.cast::().wrapping_offset(offset).cast::() + (ptr as *mut u8).wrapping_offset(offset) as *mut T + } + + #[must_use] + #[inline] + pub(crate) fn map_addr(ptr: *mut T, f: impl FnOnce(usize) -> usize) -> *mut T + where + T: Sized, + { + self::with_addr(ptr, f(addr(ptr))) + } +} + +// These test are snatched from std as well. +#[cfg(test)] +mod tests { + use std::panic; + use std::{sync::mpsc::channel, thread}; + + use super::OnceCell; + + impl OnceCell { + fn init(&self, f: impl FnOnce() -> T) { + enum Void {} + let _ = self.initialize(|| Ok::(f())); + } + } + + #[test] + fn smoke_once() { + static O: OnceCell<()> = OnceCell::new(); + let mut a = 0; + O.init(|| a += 1); + assert_eq!(a, 1); + O.init(|| a += 1); + assert_eq!(a, 1); + } + + #[test] + fn stampede_once() { + static O: OnceCell<()> = OnceCell::new(); + static mut RUN: bool = false; + + let (tx, rx) = channel(); + for _ in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..4 { + thread::yield_now() + } + unsafe { + O.init(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + tx.send(()).unwrap(); + }); + } + + unsafe { + O.init(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + + for _ in 0..10 { + rx.recv().unwrap(); + } + } + + #[test] + fn poison_bad() { + static O: OnceCell<()> = OnceCell::new(); + + // poison the once + let t = panic::catch_unwind(|| { + O.init(|| panic!()); + }); + assert!(t.is_err()); + + // we can subvert poisoning, however + let mut called = false; + O.init(|| { + called = true; + }); + assert!(called); + + // once any success happens, we stop propagating the poison + O.init(|| {}); + } + + #[test] + fn wait_for_force_to_finish() { + static O: OnceCell<()> = OnceCell::new(); + + // poison the once + let t = panic::catch_unwind(|| { + O.init(|| panic!()); + }); + assert!(t.is_err()); + + // make sure someone's waiting inside the once via a force + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let t1 = thread::spawn(move || { + O.init(|| { + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + }); + }); + + rx1.recv().unwrap(); + + // put another waiter on the once + let t2 = thread::spawn(|| { + let mut called = false; + O.init(|| { + called = true; + }); + assert!(!called); + }); + + tx2.send(()).unwrap(); + + assert!(t1.join().is_ok()); + assert!(t2.join().is_ok()); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn test_size() { + use std::mem::size_of; + + assert_eq!(size_of::>(), 4 * size_of::()); + } +} diff --git a/third_party/rust/once_cell/v1/crate/src/lib.rs b/third_party/rust/once_cell/v1/crate/src/lib.rs new file mode 100644 index 000000000000..41313f73668d --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/src/lib.rs @@ -0,0 +1,1378 @@ +//! # Overview +//! +//! `once_cell` provides two new cell-like types, [`unsync::OnceCell`] and [`sync::OnceCell`]. A `OnceCell` +//! might store arbitrary non-`Copy` types, can be assigned to at most once and provides direct access +//! to the stored contents. The core API looks *roughly* like this (and there's much more inside, read on!): +//! +//! ```rust,ignore +//! impl OnceCell { +//! const fn new() -> OnceCell { ... } +//! fn set(&self, value: T) -> Result<(), T> { ... } +//! fn get(&self) -> Option<&T> { ... } +//! } +//! ``` +//! +//! Note that, like with [`RefCell`] and [`Mutex`], the `set` method requires only a shared reference. +//! Because of the single assignment restriction `get` can return a `&T` instead of `Ref` +//! or `MutexGuard`. +//! +//! The `sync` flavor is thread-safe (that is, implements the [`Sync`] trait), while the `unsync` one is not. +//! +//! [`unsync::OnceCell`]: unsync/struct.OnceCell.html +//! [`sync::OnceCell`]: sync/struct.OnceCell.html +//! [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +//! [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html +//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html +//! +//! # Recipes +//! +//! `OnceCell` might be useful for a variety of patterns. +//! +//! ## Safe Initialization of Global Data +//! +//! ```rust +//! use std::{env, io}; +//! +//! use once_cell::sync::OnceCell; +//! +//! #[derive(Debug)] +//! pub struct Logger { +//! // ... +//! } +//! static INSTANCE: OnceCell = OnceCell::new(); +//! +//! impl Logger { +//! pub fn global() -> &'static Logger { +//! INSTANCE.get().expect("logger is not initialized") +//! } +//! +//! fn from_cli(args: env::Args) -> Result { +//! // ... +//! # Ok(Logger {}) +//! } +//! } +//! +//! fn main() { +//! let logger = Logger::from_cli(env::args()).unwrap(); +//! INSTANCE.set(logger).unwrap(); +//! // use `Logger::global()` from now on +//! } +//! ``` +//! +//! ## Lazy Initialized Global Data +//! +//! This is essentially the `lazy_static!` macro, but without a macro. +//! +//! ```rust +//! use std::{sync::Mutex, collections::HashMap}; +//! +//! use once_cell::sync::OnceCell; +//! +//! fn global_data() -> &'static Mutex> { +//! static INSTANCE: OnceCell>> = OnceCell::new(); +//! INSTANCE.get_or_init(|| { +//! let mut m = HashMap::new(); +//! m.insert(13, "Spica".to_string()); +//! m.insert(74, "Hoyten".to_string()); +//! Mutex::new(m) +//! }) +//! } +//! ``` +//! +//! There are also the [`sync::Lazy`] and [`unsync::Lazy`] convenience types to streamline this pattern: +//! +//! ```rust +//! use std::{sync::Mutex, collections::HashMap}; +//! use once_cell::sync::Lazy; +//! +//! static GLOBAL_DATA: Lazy>> = Lazy::new(|| { +//! let mut m = HashMap::new(); +//! m.insert(13, "Spica".to_string()); +//! m.insert(74, "Hoyten".to_string()); +//! Mutex::new(m) +//! }); +//! +//! fn main() { +//! println!("{:?}", GLOBAL_DATA.lock().unwrap()); +//! } +//! ``` +//! +//! Note that the variable that holds `Lazy` is declared as `static`, *not* +//! `const`. This is important: using `const` instead compiles, but works wrong. +//! +//! [`sync::Lazy`]: sync/struct.Lazy.html +//! [`unsync::Lazy`]: unsync/struct.Lazy.html +//! +//! ## General purpose lazy evaluation +//! +//! Unlike `lazy_static!`, `Lazy` works with local variables. +//! +//! ```rust +//! use once_cell::unsync::Lazy; +//! +//! fn main() { +//! let ctx = vec![1, 2, 3]; +//! let thunk = Lazy::new(|| { +//! ctx.iter().sum::() +//! }); +//! assert_eq!(*thunk, 6); +//! } +//! ``` +//! +//! If you need a lazy field in a struct, you probably should use `OnceCell` +//! directly, because that will allow you to access `self` during initialization. +//! +//! ```rust +//! use std::{fs, path::PathBuf}; +//! +//! use once_cell::unsync::OnceCell; +//! +//! struct Ctx { +//! config_path: PathBuf, +//! config: OnceCell, +//! } +//! +//! impl Ctx { +//! pub fn get_config(&self) -> Result<&str, std::io::Error> { +//! let cfg = self.config.get_or_try_init(|| { +//! fs::read_to_string(&self.config_path) +//! })?; +//! Ok(cfg.as_str()) +//! } +//! } +//! ``` +//! +//! ## Lazily Compiled Regex +//! +//! This is a `regex!` macro which takes a string literal and returns an +//! *expression* that evaluates to a `&'static Regex`: +//! +//! ``` +//! macro_rules! regex { +//! ($re:literal $(,)?) => {{ +//! static RE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); +//! RE.get_or_init(|| regex::Regex::new($re).unwrap()) +//! }}; +//! } +//! ``` +//! +//! This macro can be useful to avoid the "compile regex on every loop iteration" problem. +//! +//! ## Runtime `include_bytes!` +//! +//! The `include_bytes` macro is useful to include test resources, but it slows +//! down test compilation a lot. An alternative is to load the resources at +//! runtime: +//! +//! ``` +//! use std::path::Path; +//! +//! use once_cell::sync::OnceCell; +//! +//! pub struct TestResource { +//! path: &'static str, +//! cell: OnceCell>, +//! } +//! +//! impl TestResource { +//! pub const fn new(path: &'static str) -> TestResource { +//! TestResource { path, cell: OnceCell::new() } +//! } +//! pub fn bytes(&self) -> &[u8] { +//! self.cell.get_or_init(|| { +//! let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); +//! let path = Path::new(dir.as_str()).join(self.path); +//! std::fs::read(&path).unwrap_or_else(|_err| { +//! panic!("failed to load test resource: {}", path.display()) +//! }) +//! }).as_slice() +//! } +//! } +//! +//! static TEST_IMAGE: TestResource = TestResource::new("test_data/lena.png"); +//! +//! #[test] +//! fn test_sobel_filter() { +//! let rgb: &[u8] = TEST_IMAGE.bytes(); +//! // ... +//! # drop(rgb); +//! } +//! ``` +//! +//! ## `lateinit` +//! +//! `LateInit` type for delayed initialization. It is reminiscent of Kotlin's +//! `lateinit` keyword and allows construction of cyclic data structures: +//! +//! +//! ``` +//! use once_cell::sync::OnceCell; +//! +//! #[derive(Debug)] +//! pub struct LateInit { cell: OnceCell } +//! +//! impl LateInit { +//! pub fn init(&self, value: T) { +//! assert!(self.cell.set(value).is_ok()) +//! } +//! } +//! +//! impl Default for LateInit { +//! fn default() -> Self { LateInit { cell: OnceCell::default() } } +//! } +//! +//! impl std::ops::Deref for LateInit { +//! type Target = T; +//! fn deref(&self) -> &T { +//! self.cell.get().unwrap() +//! } +//! } +//! +//! #[derive(Default, Debug)] +//! struct A<'a> { +//! b: LateInit<&'a B<'a>>, +//! } +//! +//! #[derive(Default, Debug)] +//! struct B<'a> { +//! a: LateInit<&'a A<'a>> +//! } +//! +//! fn build_cycle() { +//! let a = A::default(); +//! let b = B::default(); +//! a.b.init(&b); +//! b.a.init(&a); +//! println!("{:?}", a.b.a.b.a); +//! } +//! ``` +//! +//! # Comparison with std +//! +//! |`!Sync` types | Access Mode | Drawbacks | +//! |----------------------|------------------------|-----------------------------------------------| +//! |`Cell` | `T` | requires `T: Copy` for `get` | +//! |`RefCell` | `RefMut` / `Ref` | may panic at runtime | +//! |`unsync::OnceCell` | `&T` | assignable only once | +//! +//! |`Sync` types | Access Mode | Drawbacks | +//! |----------------------|------------------------|-----------------------------------------------| +//! |`AtomicT` | `T` | works only with certain `Copy` types | +//! |`Mutex` | `MutexGuard` | may deadlock at runtime, may block the thread | +//! |`sync::OnceCell` | `&T` | assignable only once, may block the thread | +//! +//! Technically, calling `get_or_init` will also cause a panic or a deadlock if it recursively calls +//! itself. However, because the assignment can happen only once, such cases should be more rare than +//! equivalents with `RefCell` and `Mutex`. +//! +//! # Minimum Supported `rustc` Version +//! +//! This crate's minimum supported `rustc` version is `1.56.0`. +//! +//! If only the `std` feature is enabled, MSRV will be updated conservatively, supporting at least latest 8 versions of the compiler. +//! When using other features, like `parking_lot`, MSRV might be updated more frequently, up to the latest stable. +//! In both cases, increasing MSRV is *not* considered a semver-breaking change. +//! +//! # Implementation details +//! +//! The implementation is based on the [`lazy_static`](https://github.com/rust-lang-nursery/lazy-static.rs/) +//! and [`lazy_cell`](https://github.com/indiv0/lazycell/) crates and [`std::sync::Once`]. In some sense, +//! `once_cell` just streamlines and unifies those APIs. +//! +//! To implement a sync flavor of `OnceCell`, this crates uses either a custom +//! re-implementation of `std::sync::Once` or `parking_lot::Mutex`. This is +//! controlled by the `parking_lot` feature (disabled by default). Performance +//! is the same for both cases, but the `parking_lot` based `OnceCell` is +//! smaller by up to 16 bytes. +//! +//! This crate uses `unsafe`. +//! +//! [`std::sync::Once`]: https://doc.rust-lang.org/std/sync/struct.Once.html +//! +//! # F.A.Q. +//! +//! **Should I use lazy_static or once_cell?** +//! +//! To the first approximation, `once_cell` is both more flexible and more convenient than `lazy_static` +//! and should be preferred. +//! +//! Unlike `once_cell`, `lazy_static` supports spinlock-based implementation of blocking which works with +//! `#![no_std]`. +//! +//! `lazy_static` has received significantly more real world testing, but `once_cell` is also a widely +//! used crate. +//! +//! **Should I use the sync or unsync flavor?** +//! +//! Because Rust compiler checks thread safety for you, it's impossible to accidentally use `unsync` where +//! `sync` is required. So, use `unsync` in single-threaded code and `sync` in multi-threaded. It's easy +//! to switch between the two if code becomes multi-threaded later. +//! +//! At the moment, `unsync` has an additional benefit that reentrant initialization causes a panic, which +//! might be easier to debug than a deadlock. +//! +//! **Does this crate support async?** +//! +//! No, but you can use [`async_once_cell`](https://crates.io/crates/async_once_cell) instead. +//! +//! # Related crates +//! +//! * [double-checked-cell](https://github.com/niklasf/double-checked-cell) +//! * [lazy-init](https://crates.io/crates/lazy-init) +//! * [lazycell](https://crates.io/crates/lazycell) +//! * [mitochondria](https://crates.io/crates/mitochondria) +//! * [lazy_static](https://crates.io/crates/lazy_static) +//! * [async_once_cell](https://crates.io/crates/async_once_cell) +//! +//! Most of this crate's functionality is available in `std` in nightly Rust. +//! See the [tracking issue](https://github.com/rust-lang/rust/issues/74465). + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(all(feature = "critical-section", not(feature = "std")))] +#[path = "imp_cs.rs"] +mod imp; + +#[cfg(all(feature = "std", feature = "parking_lot"))] +#[path = "imp_pl.rs"] +mod imp; + +#[cfg(all(feature = "std", not(feature = "parking_lot")))] +#[path = "imp_std.rs"] +mod imp; + +/// Single-threaded version of `OnceCell`. +pub mod unsync { + use core::{ + cell::{Cell, UnsafeCell}, + fmt, mem, + ops::{Deref, DerefMut}, + panic::{RefUnwindSafe, UnwindSafe}, + }; + + use super::unwrap_unchecked; + + /// A cell which can be written to only once. It is not thread safe. + /// + /// Unlike [`std::cell::RefCell`], a `OnceCell` provides simple `&` + /// references to the contents. + /// + /// [`std::cell::RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html + /// + /// # Example + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// let value: &String = cell.get_or_init(|| { + /// "Hello, World!".to_string() + /// }); + /// assert_eq!(value, "Hello, World!"); + /// assert!(cell.get().is_some()); + /// ``` + pub struct OnceCell { + // Invariant: written to at most once. + inner: UnsafeCell>, + } + + // Similarly to a `Sync` bound on `sync::OnceCell`, we can use + // `&unsync::OnceCell` to sneak a `T` through `catch_unwind`, + // by initializing the cell in closure and extracting the value in the + // `Drop`. + impl RefUnwindSafe for OnceCell {} + impl UnwindSafe for OnceCell {} + + impl Default for OnceCell { + fn default() -> Self { + Self::new() + } + } + + impl fmt::Debug for OnceCell { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("OnceCell").field(v).finish(), + None => f.write_str("OnceCell(Uninit)"), + } + } + } + + impl Clone for OnceCell { + fn clone(&self) -> OnceCell { + match self.get() { + Some(value) => OnceCell::with_value(value.clone()), + None => OnceCell::new(), + } + } + + fn clone_from(&mut self, source: &Self) { + match (self.get_mut(), source.get()) { + (Some(this), Some(source)) => this.clone_from(source), + _ => *self = source.clone(), + } + } + } + + impl PartialEq for OnceCell { + fn eq(&self, other: &Self) -> bool { + self.get() == other.get() + } + } + + impl Eq for OnceCell {} + + impl From for OnceCell { + fn from(value: T) -> Self { + OnceCell::with_value(value) + } + } + + impl OnceCell { + /// Creates a new empty cell. + pub const fn new() -> OnceCell { + OnceCell { inner: UnsafeCell::new(None) } + } + + /// Creates a new initialized cell. + pub const fn with_value(value: T) -> OnceCell { + OnceCell { inner: UnsafeCell::new(Some(value)) } + } + + /// Gets a reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + #[inline] + pub fn get(&self) -> Option<&T> { + // Safe due to `inner`'s invariant + unsafe { &*self.inner.get() }.as_ref() + } + + /// Gets a mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + /// + /// This method is allowed to violate the invariant of writing to a `OnceCell` + /// at most once because it requires `&mut` access to `self`. As with all + /// interior mutability, `&mut` access permits arbitrary modification: + /// + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let mut cell: OnceCell = OnceCell::new(); + /// cell.set(92).unwrap(); + /// *cell.get_mut().unwrap() = 93; + /// assert_eq!(cell.get(), Some(&93)); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> Option<&mut T> { + // Safe because we have unique access + unsafe { &mut *self.inner.get() }.as_mut() + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. + /// + /// # Example + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.set(92), Ok(())); + /// assert_eq!(cell.set(62), Err(62)); + /// + /// assert!(cell.get().is_some()); + /// ``` + pub fn set(&self, value: T) -> Result<(), T> { + match self.try_insert(value) { + Ok(_) => Ok(()), + Err((_, value)) => Err(value), + } + } + + /// Like [`set`](Self::set), but also returns a reference to the final cell value. + /// + /// # Example + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.try_insert(92), Ok(&92)); + /// assert_eq!(cell.try_insert(62), Err((&92, 62))); + /// + /// assert!(cell.get().is_some()); + /// ``` + pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { + if let Some(old) = self.get() { + return Err((old, value)); + } + + let slot = unsafe { &mut *self.inner.get() }; + // This is the only place where we set the slot, no races + // due to reentrancy/concurrency are possible, and we've + // checked that slot is currently `None`, so this write + // maintains the `inner`'s invariant. + *slot = Some(value); + Ok(unsafe { unwrap_unchecked(slot.as_ref()) }) + } + + /// Gets the contents of the cell, initializing it with `f` + /// if the cell was empty. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. Doing + /// so results in a panic. + /// + /// # Example + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// let value = cell.get_or_init(|| 92); + /// assert_eq!(value, &92); + /// let value = cell.get_or_init(|| unreachable!()); + /// assert_eq!(value, &92); + /// ``` + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + enum Void {} + match self.get_or_try_init(|| Ok::(f())) { + Ok(val) => val, + Err(void) => match void {}, + } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. Doing + /// so results in a panic. + /// + /// # Example + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + /// assert!(cell.get().is_none()); + /// let value = cell.get_or_try_init(|| -> Result { + /// Ok(92) + /// }); + /// assert_eq!(value, Ok(&92)); + /// assert_eq!(cell.get(), Some(&92)) + /// ``` + pub fn get_or_try_init(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result, + { + if let Some(val) = self.get() { + return Ok(val); + } + let val = f()?; + // Note that *some* forms of reentrant initialization might lead to + // UB (see `reentrant_init` test). I believe that just removing this + // `assert`, while keeping `set/get` would be sound, but it seems + // better to panic, rather than to silently use an old value. + assert!(self.set(val).is_ok(), "reentrant init"); + Ok(unsafe { unwrap_unchecked(self.get()) }) + } + + /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. + /// + /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. + /// + /// # Examples + /// + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let mut cell: OnceCell = OnceCell::new(); + /// assert_eq!(cell.take(), None); + /// + /// let mut cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.take(), Some("hello".to_string())); + /// assert_eq!(cell.get(), None); + /// ``` + /// + /// This method is allowed to violate the invariant of writing to a `OnceCell` + /// at most once because it requires `&mut` access to `self`. As with all + /// interior mutability, `&mut` access permits arbitrary modification: + /// + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let mut cell: OnceCell = OnceCell::new(); + /// cell.set(92).unwrap(); + /// cell = OnceCell::new(); + /// ``` + pub fn take(&mut self) -> Option { + mem::replace(self, Self::default()).into_inner() + } + + /// Consumes the `OnceCell`, returning the wrapped value. + /// + /// Returns `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let cell: OnceCell = OnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + pub fn into_inner(self) -> Option { + // Because `into_inner` takes `self` by value, the compiler statically verifies + // that it is not currently borrowed. So it is safe to move out `Option`. + self.inner.into_inner() + } + } + + /// A value which is initialized on the first access. + /// + /// # Example + /// ``` + /// use once_cell::unsync::Lazy; + /// + /// let lazy: Lazy = Lazy::new(|| { + /// println!("initializing"); + /// 92 + /// }); + /// println!("ready"); + /// println!("{}", *lazy); + /// println!("{}", *lazy); + /// + /// // Prints: + /// // ready + /// // initializing + /// // 92 + /// // 92 + /// ``` + pub struct Lazy T> { + cell: OnceCell, + init: Cell>, + } + + impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} + + impl fmt::Debug for Lazy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + } + } + + impl Lazy { + /// Creates a new lazy value with the given initializing function. + /// + /// # Example + /// ``` + /// # fn main() { + /// use once_cell::unsync::Lazy; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = Lazy::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// # } + /// ``` + pub const fn new(init: F) -> Lazy { + Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } + } + + /// Consumes this `Lazy` returning the stored value. + /// + /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. + pub fn into_value(this: Lazy) -> Result { + let cell = this.cell; + let init = this.init; + cell.into_inner().ok_or_else(|| { + init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned")) + }) + } + } + + impl T> Lazy { + /// Forces the evaluation of this lazy value and returns a reference to + /// the result. + /// + /// This is equivalent to the `Deref` impl, but is explicit. + /// + /// # Example + /// ``` + /// use once_cell::unsync::Lazy; + /// + /// let lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + pub fn force(this: &Lazy) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("Lazy instance has previously been poisoned"), + }) + } + + /// Forces the evaluation of this lazy value and returns a mutable reference to + /// the result. + /// + /// This is equivalent to the `DerefMut` impl, but is explicit. + /// + /// # Example + /// ``` + /// use once_cell::unsync::Lazy; + /// + /// let mut lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::force_mut(&mut lazy), &92); + /// assert_eq!(*lazy, 92); + /// ``` + pub fn force_mut(this: &mut Lazy) -> &mut T { + Self::force(this); + Self::get_mut(this).unwrap_or_else(|| unreachable!()) + } + + /// Gets the reference to the result of this lazy value if + /// it was initialized, otherwise returns `None`. + /// + /// # Example + /// ``` + /// use once_cell::unsync::Lazy; + /// + /// let lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::get(&lazy), None); + /// assert_eq!(&*lazy, &92); + /// assert_eq!(Lazy::get(&lazy), Some(&92)); + /// ``` + pub fn get(this: &Lazy) -> Option<&T> { + this.cell.get() + } + + /// Gets the mutable reference to the result of this lazy value if + /// it was initialized, otherwise returns `None`. + /// + /// # Example + /// ``` + /// use once_cell::unsync::Lazy; + /// + /// let mut lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::get_mut(&mut lazy), None); + /// assert_eq!(*lazy, 92); + /// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92)); + /// ``` + pub fn get_mut(this: &mut Lazy) -> Option<&mut T> { + this.cell.get_mut() + } + } + + impl T> Deref for Lazy { + type Target = T; + fn deref(&self) -> &T { + Lazy::force(self) + } + } + + impl T> DerefMut for Lazy { + fn deref_mut(&mut self) -> &mut T { + Lazy::force(self); + self.cell.get_mut().unwrap_or_else(|| unreachable!()) + } + } + + impl Default for Lazy { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> Lazy { + Lazy::new(T::default) + } + } +} + +/// Thread-safe, blocking version of `OnceCell`. +#[cfg(any(feature = "std", feature = "critical-section"))] +pub mod sync { + use core::{ + cell::Cell, + fmt, mem, + ops::{Deref, DerefMut}, + panic::RefUnwindSafe, + }; + + use super::{imp::OnceCell as Imp, unwrap_unchecked}; + + /// A thread-safe cell which can be written to only once. + /// + /// `OnceCell` provides `&` references to the contents without RAII guards. + /// + /// Reading a non-`None` value out of `OnceCell` establishes a + /// happens-before relationship with a corresponding write. For example, if + /// thread A initializes the cell with `get_or_init(f)`, and thread B + /// subsequently reads the result of this call, B also observes all the side + /// effects of `f`. + /// + /// # Example + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// static CELL: OnceCell = OnceCell::new(); + /// assert!(CELL.get().is_none()); + /// + /// std::thread::spawn(|| { + /// let value: &String = CELL.get_or_init(|| { + /// "Hello, World!".to_string() + /// }); + /// assert_eq!(value, "Hello, World!"); + /// }).join().unwrap(); + /// + /// let value: Option<&String> = CELL.get(); + /// assert!(value.is_some()); + /// assert_eq!(value.unwrap().as_str(), "Hello, World!"); + /// ``` + pub struct OnceCell(Imp); + + impl Default for OnceCell { + fn default() -> OnceCell { + OnceCell::new() + } + } + + impl fmt::Debug for OnceCell { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.get() { + Some(v) => f.debug_tuple("OnceCell").field(v).finish(), + None => f.write_str("OnceCell(Uninit)"), + } + } + } + + impl Clone for OnceCell { + fn clone(&self) -> OnceCell { + match self.get() { + Some(value) => Self::with_value(value.clone()), + None => Self::new(), + } + } + + fn clone_from(&mut self, source: &Self) { + match (self.get_mut(), source.get()) { + (Some(this), Some(source)) => this.clone_from(source), + _ => *self = source.clone(), + } + } + } + + impl From for OnceCell { + fn from(value: T) -> Self { + Self::with_value(value) + } + } + + impl PartialEq for OnceCell { + fn eq(&self, other: &OnceCell) -> bool { + self.get() == other.get() + } + } + + impl Eq for OnceCell {} + + impl OnceCell { + /// Creates a new empty cell. + pub const fn new() -> OnceCell { + OnceCell(Imp::new()) + } + + /// Creates a new initialized cell. + pub const fn with_value(value: T) -> OnceCell { + OnceCell(Imp::with_value(value)) + } + + /// Gets the reference to the underlying value. + /// + /// Returns `None` if the cell is empty, or being initialized. This + /// method never blocks. + pub fn get(&self) -> Option<&T> { + if self.0.is_initialized() { + // Safe b/c value is initialized. + Some(unsafe { self.get_unchecked() }) + } else { + None + } + } + + /// Gets the reference to the underlying value, blocking the current + /// thread until it is set. + /// + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// let mut cell = std::sync::Arc::new(OnceCell::new()); + /// let t = std::thread::spawn({ + /// let cell = std::sync::Arc::clone(&cell); + /// move || cell.set(92).unwrap() + /// }); + /// + /// // Returns immediately, but might return None. + /// let _value_or_none = cell.get(); + /// + /// // Will return 92, but might block until the other thread does `.set`. + /// let value: &u32 = cell.wait(); + /// assert_eq!(*value, 92); + /// t.join().unwrap(); + /// ``` + #[cfg(feature = "std")] + pub fn wait(&self) -> &T { + if !self.0.is_initialized() { + self.0.wait() + } + debug_assert!(self.0.is_initialized()); + // Safe b/c of the wait call above and the fact that we didn't + // relinquish our borrow. + unsafe { self.get_unchecked() } + } + + /// Gets the mutable reference to the underlying value. + /// + /// Returns `None` if the cell is empty. + /// + /// This method is allowed to violate the invariant of writing to a `OnceCell` + /// at most once because it requires `&mut` access to `self`. As with all + /// interior mutability, `&mut` access permits arbitrary modification: + /// + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// let mut cell: OnceCell = OnceCell::new(); + /// cell.set(92).unwrap(); + /// cell = OnceCell::new(); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> Option<&mut T> { + self.0.get_mut() + } + + /// Get the reference to the underlying value, without checking if the + /// cell is initialized. + /// + /// # Safety + /// + /// Caller must ensure that the cell is in initialized state, and that + /// the contents are acquired by (synchronized to) this thread. + #[inline] + pub unsafe fn get_unchecked(&self) -> &T { + self.0.get_unchecked() + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. + /// + /// # Example + /// + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// static CELL: OnceCell = OnceCell::new(); + /// + /// fn main() { + /// assert!(CELL.get().is_none()); + /// + /// std::thread::spawn(|| { + /// assert_eq!(CELL.set(92), Ok(())); + /// }).join().unwrap(); + /// + /// assert_eq!(CELL.set(62), Err(62)); + /// assert_eq!(CELL.get(), Some(&92)); + /// } + /// ``` + pub fn set(&self, value: T) -> Result<(), T> { + match self.try_insert(value) { + Ok(_) => Ok(()), + Err((_, value)) => Err(value), + } + } + + /// Like [`set`](Self::set), but also returns a reference to the final cell value. + /// + /// # Example + /// + /// ``` + /// use once_cell::unsync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.try_insert(92), Ok(&92)); + /// assert_eq!(cell.try_insert(62), Err((&92, 62))); + /// + /// assert!(cell.get().is_some()); + /// ``` + pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { + let mut value = Some(value); + let res = self.get_or_init(|| unsafe { unwrap_unchecked(value.take()) }); + match value { + None => Ok(res), + Some(value) => Err((res, value)), + } + } + + /// Gets the contents of the cell, initializing it with `f` if the cell + /// was empty. + /// + /// Many threads may call `get_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. The + /// exact outcome is unspecified. Current implementation deadlocks, but + /// this may be changed to a panic in the future. + /// + /// # Example + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// let value = cell.get_or_init(|| 92); + /// assert_eq!(value, &92); + /// let value = cell.get_or_init(|| unreachable!()); + /// assert_eq!(value, &92); + /// ``` + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> T, + { + enum Void {} + match self.get_or_try_init(|| Ok::(f())) { + Ok(val) => val, + Err(void) => match void {}, + } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and + /// the cell remains uninitialized. + /// + /// It is an error to reentrantly initialize the cell from `f`. + /// The exact outcome is unspecified. Current implementation + /// deadlocks, but this may be changed to a panic in the future. + /// + /// # Example + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + /// assert!(cell.get().is_none()); + /// let value = cell.get_or_try_init(|| -> Result { + /// Ok(92) + /// }); + /// assert_eq!(value, Ok(&92)); + /// assert_eq!(cell.get(), Some(&92)) + /// ``` + pub fn get_or_try_init(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result, + { + // Fast path check + if let Some(value) = self.get() { + return Ok(value); + } + + self.0.initialize(f)?; + + // Safe b/c value is initialized. + debug_assert!(self.0.is_initialized()); + Ok(unsafe { self.get_unchecked() }) + } + + /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. + /// + /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. + /// + /// # Examples + /// + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// let mut cell: OnceCell = OnceCell::new(); + /// assert_eq!(cell.take(), None); + /// + /// let mut cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.take(), Some("hello".to_string())); + /// assert_eq!(cell.get(), None); + /// ``` + /// + /// This method is allowed to violate the invariant of writing to a `OnceCell` + /// at most once because it requires `&mut` access to `self`. As with all + /// interior mutability, `&mut` access permits arbitrary modification: + /// + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// let mut cell: OnceCell = OnceCell::new(); + /// cell.set(92).unwrap(); + /// cell = OnceCell::new(); + /// ``` + pub fn take(&mut self) -> Option { + mem::replace(self, Self::default()).into_inner() + } + + /// Consumes the `OnceCell`, returning the wrapped value. Returns + /// `None` if the cell was empty. + /// + /// # Examples + /// + /// ``` + /// use once_cell::sync::OnceCell; + /// + /// let cell: OnceCell = OnceCell::new(); + /// assert_eq!(cell.into_inner(), None); + /// + /// let cell = OnceCell::new(); + /// cell.set("hello".to_string()).unwrap(); + /// assert_eq!(cell.into_inner(), Some("hello".to_string())); + /// ``` + #[inline] + pub fn into_inner(self) -> Option { + self.0.into_inner() + } + } + + /// A value which is initialized on the first access. + /// + /// This type is thread-safe and can be used in statics. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// use once_cell::sync::Lazy; + /// + /// static HASHMAP: Lazy> = Lazy::new(|| { + /// println!("initializing"); + /// let mut m = HashMap::new(); + /// m.insert(13, "Spica".to_string()); + /// m.insert(74, "Hoyten".to_string()); + /// m + /// }); + /// + /// fn main() { + /// println!("ready"); + /// std::thread::spawn(|| { + /// println!("{:?}", HASHMAP.get(&13)); + /// }).join().unwrap(); + /// println!("{:?}", HASHMAP.get(&74)); + /// + /// // Prints: + /// // ready + /// // initializing + /// // Some("Spica") + /// // Some("Hoyten") + /// } + /// ``` + pub struct Lazy T> { + cell: OnceCell, + init: Cell>, + } + + impl fmt::Debug for Lazy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() + } + } + + // We never create a `&F` from a `&Lazy` so it is fine to not impl + // `Sync` for `F`. We do create a `&mut Option` in `force`, but this is + // properly synchronized, so it only happens once so it also does not + // contribute to this impl. + unsafe impl Sync for Lazy where OnceCell: Sync {} + // auto-derived `Send` impl is OK. + + impl RefUnwindSafe for Lazy where OnceCell: RefUnwindSafe {} + + impl Lazy { + /// Creates a new lazy value with the given initializing + /// function. + pub const fn new(f: F) -> Lazy { + Lazy { cell: OnceCell::new(), init: Cell::new(Some(f)) } + } + + /// Consumes this `Lazy` returning the stored value. + /// + /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. + pub fn into_value(this: Lazy) -> Result { + let cell = this.cell; + let init = this.init; + cell.into_inner().ok_or_else(|| { + init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned")) + }) + } + } + + impl T> Lazy { + /// Forces the evaluation of this lazy value and + /// returns a reference to the result. This is equivalent + /// to the `Deref` impl, but is explicit. + /// + /// # Example + /// ``` + /// use once_cell::sync::Lazy; + /// + /// let lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::force(&lazy), &92); + /// assert_eq!(&*lazy, &92); + /// ``` + pub fn force(this: &Lazy) -> &T { + this.cell.get_or_init(|| match this.init.take() { + Some(f) => f(), + None => panic!("Lazy instance has previously been poisoned"), + }) + } + + /// Forces the evaluation of this lazy value and + /// returns a mutable reference to the result. This is equivalent + /// to the `Deref` impl, but is explicit. + /// + /// # Example + /// ``` + /// use once_cell::sync::Lazy; + /// + /// let mut lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::force_mut(&mut lazy), &mut 92); + /// ``` + pub fn force_mut(this: &mut Lazy) -> &mut T { + Self::force(this); + Self::get_mut(this).unwrap_or_else(|| unreachable!()) + } + + /// Gets the reference to the result of this lazy value if + /// it was initialized, otherwise returns `None`. + /// + /// # Example + /// ``` + /// use once_cell::sync::Lazy; + /// + /// let lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::get(&lazy), None); + /// assert_eq!(&*lazy, &92); + /// assert_eq!(Lazy::get(&lazy), Some(&92)); + /// ``` + pub fn get(this: &Lazy) -> Option<&T> { + this.cell.get() + } + + /// Gets the reference to the result of this lazy value if + /// it was initialized, otherwise returns `None`. + /// + /// # Example + /// ``` + /// use once_cell::sync::Lazy; + /// + /// let mut lazy = Lazy::new(|| 92); + /// + /// assert_eq!(Lazy::get_mut(&mut lazy), None); + /// assert_eq!(&*lazy, &92); + /// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92)); + /// ``` + pub fn get_mut(this: &mut Lazy) -> Option<&mut T> { + this.cell.get_mut() + } + } + + impl T> Deref for Lazy { + type Target = T; + fn deref(&self) -> &T { + Lazy::force(self) + } + } + + impl T> DerefMut for Lazy { + fn deref_mut(&mut self) -> &mut T { + Lazy::force(self); + self.cell.get_mut().unwrap_or_else(|| unreachable!()) + } + } + + impl Default for Lazy { + /// Creates a new lazy value using `Default` as the initializing function. + fn default() -> Lazy { + Lazy::new(T::default) + } + } + + /// ```compile_fail + /// struct S(*mut ()); + /// unsafe impl Sync for S {} + /// + /// fn share(_: &T) {} + /// share(&once_cell::sync::OnceCell::::new()); + /// ``` + /// + /// ```compile_fail + /// struct S(*mut ()); + /// unsafe impl Sync for S {} + /// + /// fn share(_: &T) {} + /// share(&once_cell::sync::Lazy::::new(|| unimplemented!())); + /// ``` + fn _dummy() {} +} + +#[cfg(feature = "race")] +pub mod race; + +// Remove once MSRV is at least 1.58. +#[inline] +unsafe fn unwrap_unchecked(val: Option) -> T { + match val { + Some(value) => value, + None => { + debug_assert!(false); + core::hint::unreachable_unchecked() + } + } +} diff --git a/third_party/rust/once_cell/v1/crate/src/race.rs b/third_party/rust/once_cell/v1/crate/src/race.rs new file mode 100644 index 000000000000..fd255c4c7dec --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/src/race.rs @@ -0,0 +1,304 @@ +//! Thread-safe, non-blocking, "first one wins" flavor of `OnceCell`. +//! +//! If two threads race to initialize a type from the `race` module, they +//! don't block, execute initialization function together, but only one of +//! them stores the result. +//! +//! This module does not require `std` feature. +//! +//! # Atomic orderings +//! +//! All types in this module use `Acquire` and `Release` +//! [atomic orderings](Ordering) for all their operations. While this is not +//! strictly necessary for types other than `OnceBox`, it is useful for users as +//! it allows them to be certain that after `get` or `get_or_init` returns on +//! one thread, any side-effects caused by the setter thread prior to them +//! calling `set` or `get_or_init` will be made visible to that thread; without +//! it, it's possible for it to appear as if they haven't happened yet from the +//! getter thread's perspective. This is an acceptable tradeoff to make since +//! `Acquire` and `Release` have very little performance overhead on most +//! architectures versus `Relaxed`. + +#[cfg(feature = "critical-section")] +use atomic_polyfill as atomic; +#[cfg(not(feature = "critical-section"))] +use core::sync::atomic; + +use atomic::{AtomicUsize, Ordering}; +use core::num::NonZeroUsize; + +/// A thread-safe cell which can be written to only once. +#[derive(Default, Debug)] +pub struct OnceNonZeroUsize { + inner: AtomicUsize, +} + +impl OnceNonZeroUsize { + /// Creates a new empty cell. + #[inline] + pub const fn new() -> OnceNonZeroUsize { + OnceNonZeroUsize { inner: AtomicUsize::new(0) } + } + + /// Gets the underlying value. + #[inline] + pub fn get(&self) -> Option { + let val = self.inner.load(Ordering::Acquire); + NonZeroUsize::new(val) + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(())` if it was + /// full. + #[inline] + pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> { + let exchange = + self.inner.compare_exchange(0, value.get(), Ordering::AcqRel, Ordering::Acquire); + match exchange { + Ok(_) => Ok(()), + Err(_) => Err(()), + } + } + + /// Gets the contents of the cell, initializing it with `f` if the cell was + /// empty. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_init(&self, f: F) -> NonZeroUsize + where + F: FnOnce() -> NonZeroUsize, + { + enum Void {} + match self.get_or_try_init(|| Ok::(f())) { + Ok(val) => val, + Err(void) => match void {}, + } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_try_init(&self, f: F) -> Result + where + F: FnOnce() -> Result, + { + let val = self.inner.load(Ordering::Acquire); + let res = match NonZeroUsize::new(val) { + Some(it) => it, + None => { + let mut val = f()?.get(); + let exchange = + self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire); + if let Err(old) = exchange { + val = old; + } + unsafe { NonZeroUsize::new_unchecked(val) } + } + }; + Ok(res) + } +} + +/// A thread-safe cell which can be written to only once. +#[derive(Default, Debug)] +pub struct OnceBool { + inner: OnceNonZeroUsize, +} + +impl OnceBool { + /// Creates a new empty cell. + #[inline] + pub const fn new() -> OnceBool { + OnceBool { inner: OnceNonZeroUsize::new() } + } + + /// Gets the underlying value. + #[inline] + pub fn get(&self) -> Option { + self.inner.get().map(OnceBool::from_usize) + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(())` if it was + /// full. + #[inline] + pub fn set(&self, value: bool) -> Result<(), ()> { + self.inner.set(OnceBool::to_usize(value)) + } + + /// Gets the contents of the cell, initializing it with `f` if the cell was + /// empty. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_init(&self, f: F) -> bool + where + F: FnOnce() -> bool, + { + OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f()))) + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_try_init(&self, f: F) -> Result + where + F: FnOnce() -> Result, + { + self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize) + } + + #[inline] + fn from_usize(value: NonZeroUsize) -> bool { + value.get() == 1 + } + + #[inline] + fn to_usize(value: bool) -> NonZeroUsize { + unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) } + } +} + +#[cfg(feature = "alloc")] +pub use self::once_box::OnceBox; + +#[cfg(feature = "alloc")] +mod once_box { + use super::atomic::{AtomicPtr, Ordering}; + use core::{marker::PhantomData, ptr}; + + use alloc::boxed::Box; + + /// A thread-safe cell which can be written to only once. + pub struct OnceBox { + inner: AtomicPtr, + ghost: PhantomData>>, + } + + impl core::fmt::Debug for OnceBox { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "OnceBox({:?})", self.inner.load(Ordering::Relaxed)) + } + } + + impl Default for OnceBox { + fn default() -> Self { + Self::new() + } + } + + impl Drop for OnceBox { + fn drop(&mut self) { + let ptr = *self.inner.get_mut(); + if !ptr.is_null() { + drop(unsafe { Box::from_raw(ptr) }) + } + } + } + + impl OnceBox { + /// Creates a new empty cell. + pub const fn new() -> OnceBox { + OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData } + } + + /// Gets a reference to the underlying value. + pub fn get(&self) -> Option<&T> { + let ptr = self.inner.load(Ordering::Acquire); + if ptr.is_null() { + return None; + } + Some(unsafe { &*ptr }) + } + + /// Sets the contents of this cell to `value`. + /// + /// Returns `Ok(())` if the cell was empty and `Err(value)` if it was + /// full. + pub fn set(&self, value: Box) -> Result<(), Box> { + let ptr = Box::into_raw(value); + let exchange = self.inner.compare_exchange( + ptr::null_mut(), + ptr, + Ordering::AcqRel, + Ordering::Acquire, + ); + if let Err(_) = exchange { + let value = unsafe { Box::from_raw(ptr) }; + return Err(value); + } + Ok(()) + } + + /// Gets the contents of the cell, initializing it with `f` if the cell was + /// empty. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> Box, + { + enum Void {} + match self.get_or_try_init(|| Ok::, Void>(f())) { + Ok(val) => val, + Err(void) => match void {}, + } + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// If several threads concurrently run `get_or_init`, more than one `f` can + /// be called. However, all threads will return the same value, produced by + /// some `f`. + pub fn get_or_try_init(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result, E>, + { + let mut ptr = self.inner.load(Ordering::Acquire); + + if ptr.is_null() { + let val = f()?; + ptr = Box::into_raw(val); + let exchange = self.inner.compare_exchange( + ptr::null_mut(), + ptr, + Ordering::AcqRel, + Ordering::Acquire, + ); + if let Err(old) = exchange { + drop(unsafe { Box::from_raw(ptr) }); + ptr = old; + } + }; + Ok(unsafe { &*ptr }) + } + } + + unsafe impl Sync for OnceBox {} + + /// ```compile_fail + /// struct S(*mut ()); + /// unsafe impl Sync for S {} + /// + /// fn share(_: &T) {} + /// share(&once_cell::race::OnceBox::::new()); + /// ``` + fn _dummy() {} +} diff --git a/third_party/rust/once_cell/v1/crate/tests/it.rs b/third_party/rust/once_cell/v1/crate/tests/it.rs new file mode 100644 index 000000000000..d18f0a1654ba --- /dev/null +++ b/third_party/rust/once_cell/v1/crate/tests/it.rs @@ -0,0 +1,977 @@ +mod unsync { + use core::{ + cell::Cell, + sync::atomic::{AtomicUsize, Ordering::SeqCst}, + }; + + use once_cell::unsync::{Lazy, OnceCell}; + + #[test] + fn once_cell() { + let c = OnceCell::new(); + assert!(c.get().is_none()); + c.get_or_init(|| 92); + assert_eq!(c.get(), Some(&92)); + + c.get_or_init(|| panic!("Kabom!")); + assert_eq!(c.get(), Some(&92)); + } + + #[test] + fn once_cell_with_value() { + const CELL: OnceCell = OnceCell::with_value(12); + let cell = CELL; + assert_eq!(cell.get(), Some(&12)); + } + + #[test] + fn once_cell_get_mut() { + let mut c = OnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); + } + + #[test] + fn once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = OnceCell::new(); + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + assert_eq!(DROP_CNT.load(SeqCst), 1); + } + + #[test] + fn unsync_once_cell_drop_empty() { + let x = OnceCell::::new(); + drop(x); + } + + #[test] + fn clone() { + let s = OnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello".to_string()).unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(String::as_str), Some("hello")); + } + + #[test] + fn from_impl() { + assert_eq!(OnceCell::from("value").get(), Some(&"value")); + assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); + } + + #[test] + fn partialeq_impl() { + assert!(OnceCell::from("value") == OnceCell::from("value")); + assert!(OnceCell::from("foo") != OnceCell::from("bar")); + + assert!(OnceCell::::new() == OnceCell::new()); + assert!(OnceCell::::new() != OnceCell::from("value".to_owned())); + } + + #[test] + fn into_inner() { + let cell: OnceCell = OnceCell::new(); + assert_eq!(cell.into_inner(), None); + let cell = OnceCell::new(); + cell.set("hello".to_string()).unwrap(); + assert_eq!(cell.into_inner(), Some("hello".to_string())); + } + + #[test] + fn debug_impl() { + let cell = OnceCell::new(); + assert_eq!(format!("{:?}", cell), "OnceCell(Uninit)"); + cell.set("hello".to_string()).unwrap(); + assert_eq!(format!("{:?}", cell), "OnceCell(\"hello\")"); + } + + #[test] + fn lazy_new() { + let called = Cell::new(0); + let x = Lazy::new(|| { + called.set(called.get() + 1); + 92 + }); + + assert_eq!(called.get(), 0); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.get(), 1); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.get(), 1); + } + + #[test] + fn lazy_deref_mut() { + let called = Cell::new(0); + let mut x = Lazy::new(|| { + called.set(called.get() + 1); + 92 + }); + + assert_eq!(called.get(), 0); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.get(), 1); + + *x /= 2; + assert_eq!(*x, 46); + assert_eq!(called.get(), 1); + } + + #[test] + fn lazy_force_mut() { + let called = Cell::new(0); + let mut x = Lazy::new(|| { + called.set(called.get() + 1); + 92 + }); + assert_eq!(called.get(), 0); + let v = Lazy::force_mut(&mut x); + assert_eq!(called.get(), 1); + + *v /= 2; + assert_eq!(*x, 46); + assert_eq!(called.get(), 1); + } + + #[test] + fn lazy_get_mut() { + let called = Cell::new(0); + let mut x: Lazy = Lazy::new(|| { + called.set(called.get() + 1); + 92 + }); + + assert_eq!(called.get(), 0); + assert_eq!(*x, 92); + + let mut_ref: &mut u32 = Lazy::get_mut(&mut x).unwrap(); + assert_eq!(called.get(), 1); + + *mut_ref /= 2; + assert_eq!(*x, 46); + assert_eq!(called.get(), 1); + } + + #[test] + fn lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: Lazy> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + fn lazy_into_value() { + let l: Lazy = Lazy::new(|| panic!()); + assert!(matches!(Lazy::into_value(l), Err(_))); + let l = Lazy::new(|| -> i32 { 92 }); + Lazy::force(&l); + assert!(matches!(Lazy::into_value(l), Ok(92))); + } + + #[test] + #[cfg(feature = "std")] + fn lazy_poisoning() { + let x: Lazy = Lazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = std::panic::catch_unwind(|| x.len()); + assert!(res.is_err()); + } + } + + #[test] + fn aliasing_in_get() { + let x = OnceCell::new(); + x.set(42).unwrap(); + let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option` --+ + let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option` | + println!("{}", at_x); // <------- up until here ---------------------------+ + } + + #[test] + #[should_panic(expected = "reentrant init")] + fn reentrant_init() { + let x: OnceCell> = OnceCell::new(); + let dangling_ref: Cell> = Cell::new(None); + x.get_or_init(|| { + let r = x.get_or_init(|| Box::new(92)); + dangling_ref.set(Some(r)); + Box::new(62) + }); + eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); + } + + #[test] + // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 + fn arrrrrrrrrrrrrrrrrrrrrr() { + let cell = OnceCell::new(); + { + let s = String::new(); + cell.set(&s).unwrap(); + } + } +} + +#[cfg(any(feature = "std", feature = "critical-section"))] +mod sync { + use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + + #[cfg(feature = "std")] + use std::sync::Barrier; + + #[cfg(not(feature = "std"))] + use core::cell::Cell; + + use crossbeam_utils::thread::scope; + + use once_cell::sync::{Lazy, OnceCell}; + + #[test] + fn once_cell() { + let c = OnceCell::new(); + assert!(c.get().is_none()); + scope(|s| { + s.spawn(|_| { + c.get_or_init(|| 92); + assert_eq!(c.get(), Some(&92)); + }); + }) + .unwrap(); + c.get_or_init(|| panic!("Kabom!")); + assert_eq!(c.get(), Some(&92)); + } + + #[test] + fn once_cell_with_value() { + static CELL: OnceCell = OnceCell::with_value(12); + assert_eq!(CELL.get(), Some(&12)); + } + + #[test] + fn once_cell_get_mut() { + let mut c = OnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); + } + + #[test] + fn once_cell_get_unchecked() { + let c = OnceCell::new(); + c.set(92).unwrap(); + unsafe { + assert_eq!(c.get_unchecked(), &92); + } + } + + #[test] + fn once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = OnceCell::new(); + scope(|s| { + s.spawn(|_| { + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + }); + }) + .unwrap(); + assert_eq!(DROP_CNT.load(SeqCst), 1); + } + + #[test] + fn once_cell_drop_empty() { + let x = OnceCell::::new(); + drop(x); + } + + #[test] + fn clone() { + let s = OnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello".to_string()).unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(String::as_str), Some("hello")); + } + + #[test] + fn get_or_try_init() { + let cell: OnceCell = OnceCell::new(); + assert!(cell.get().is_none()); + + let res = + std::panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); + assert!(res.is_err()); + assert!(cell.get().is_none()); + + assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + + assert_eq!( + cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), + Ok(&"hello".to_string()) + ); + assert_eq!(cell.get(), Some(&"hello".to_string())); + } + + #[cfg(feature = "std")] + #[test] + fn wait() { + let cell: OnceCell = OnceCell::new(); + scope(|s| { + s.spawn(|_| cell.set("hello".to_string())); + let greeting = cell.wait(); + assert_eq!(greeting, "hello") + }) + .unwrap(); + } + + #[cfg(feature = "std")] + #[test] + fn get_or_init_stress() { + let n_threads = if cfg!(miri) { 30 } else { 1_000 }; + let n_cells = if cfg!(miri) { 30 } else { 1_000 }; + let cells: Vec<_> = std::iter::repeat_with(|| (Barrier::new(n_threads), OnceCell::new())) + .take(n_cells) + .collect(); + scope(|s| { + for t in 0..n_threads { + let cells = &cells; + s.spawn(move |_| { + for (i, (b, s)) in cells.iter().enumerate() { + b.wait(); + let j = if t % 2 == 0 { s.wait() } else { s.get_or_init(|| i) }; + assert_eq!(*j, i); + } + }); + } + }) + .unwrap(); + } + + #[test] + fn from_impl() { + assert_eq!(OnceCell::from("value").get(), Some(&"value")); + assert_ne!(OnceCell::from("foo").get(), Some(&"bar")); + } + + #[test] + fn partialeq_impl() { + assert!(OnceCell::from("value") == OnceCell::from("value")); + assert!(OnceCell::from("foo") != OnceCell::from("bar")); + + assert!(OnceCell::::new() == OnceCell::new()); + assert!(OnceCell::::new() != OnceCell::from("value".to_owned())); + } + + #[test] + fn into_inner() { + let cell: OnceCell = OnceCell::new(); + assert_eq!(cell.into_inner(), None); + let cell = OnceCell::new(); + cell.set("hello".to_string()).unwrap(); + assert_eq!(cell.into_inner(), Some("hello".to_string())); + } + + #[test] + fn debug_impl() { + let cell = OnceCell::new(); + assert_eq!(format!("{:#?}", cell), "OnceCell(Uninit)"); + cell.set(vec!["hello", "world"]).unwrap(); + assert_eq!( + format!("{:#?}", cell), + r#"OnceCell( + [ + "hello", + "world", + ], +)"# + ); + } + + #[test] + #[cfg_attr(miri, ignore)] // miri doesn't support processes + #[cfg(feature = "std")] + fn reentrant_init() { + let examples_dir = { + let mut exe = std::env::current_exe().unwrap(); + exe.pop(); + exe.pop(); + exe.push("examples"); + exe + }; + let bin = examples_dir + .join("reentrant_init_deadlocks") + .with_extension(std::env::consts::EXE_EXTENSION); + let mut guard = Guard { child: std::process::Command::new(bin).spawn().unwrap() }; + std::thread::sleep(std::time::Duration::from_secs(2)); + let status = guard.child.try_wait().unwrap(); + assert!(status.is_none()); + + struct Guard { + child: std::process::Child, + } + + impl Drop for Guard { + fn drop(&mut self) { + let _ = self.child.kill(); + } + } + } + + #[cfg(not(feature = "std"))] + #[test] + #[should_panic(expected = "reentrant init")] + fn reentrant_init() { + let x: OnceCell> = OnceCell::new(); + let dangling_ref: Cell> = Cell::new(None); + x.get_or_init(|| { + let r = x.get_or_init(|| Box::new(92)); + dangling_ref.set(Some(r)); + Box::new(62) + }); + eprintln!("use after free: {:?}", dangling_ref.get().unwrap()); + } + + #[test] + fn lazy_new() { + let called = AtomicUsize::new(0); + let x = Lazy::new(|| { + called.fetch_add(1, SeqCst); + 92 + }); + + assert_eq!(called.load(SeqCst), 0); + + scope(|s| { + s.spawn(|_| { + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.load(SeqCst), 1); + }); + }) + .unwrap(); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.load(SeqCst), 1); + } + + #[test] + fn lazy_deref_mut() { + let called = AtomicUsize::new(0); + let mut x = Lazy::new(|| { + called.fetch_add(1, SeqCst); + 92 + }); + + assert_eq!(called.load(SeqCst), 0); + + let y = *x - 30; + assert_eq!(y, 62); + assert_eq!(called.load(SeqCst), 1); + + *x /= 2; + assert_eq!(*x, 46); + assert_eq!(called.load(SeqCst), 1); + } + + #[test] + fn lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: Lazy> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); + } + + #[test] + fn static_lazy() { + static XS: Lazy> = Lazy::new(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }); + scope(|s| { + s.spawn(|_| { + assert_eq!(&*XS, &vec![1, 2, 3]); + }); + }) + .unwrap(); + assert_eq!(&*XS, &vec![1, 2, 3]); + } + + #[test] + fn static_lazy_via_fn() { + fn xs() -> &'static Vec { + static XS: OnceCell> = OnceCell::new(); + XS.get_or_init(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }) + } + assert_eq!(xs(), &vec![1, 2, 3]); + } + + #[test] + fn lazy_into_value() { + let l: Lazy = Lazy::new(|| panic!()); + assert!(matches!(Lazy::into_value(l), Err(_))); + let l = Lazy::new(|| -> i32 { 92 }); + Lazy::force(&l); + assert!(matches!(Lazy::into_value(l), Ok(92))); + } + + #[test] + fn lazy_poisoning() { + let x: Lazy = Lazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = std::panic::catch_unwind(|| x.len()); + assert!(res.is_err()); + } + } + + #[test] + fn once_cell_is_sync_send() { + fn assert_traits() {} + assert_traits::>(); + assert_traits::>(); + } + + #[test] + fn eval_once_macro() { + macro_rules! eval_once { + (|| -> $ty:ty { + $($body:tt)* + }) => {{ + static ONCE_CELL: OnceCell<$ty> = OnceCell::new(); + fn init() -> $ty { + $($body)* + } + ONCE_CELL.get_or_init(init) + }}; + } + + let fib: &'static Vec = eval_once! { + || -> Vec { + let mut res = vec![1, 1]; + for i in 0..10 { + let next = res[i] + res[i + 1]; + res.push(next); + } + res + } + }; + assert_eq!(fib[5], 8) + } + + #[test] + fn once_cell_does_not_leak_partially_constructed_boxes() { + let n_tries = if cfg!(miri) { 10 } else { 100 }; + let n_readers = 10; + let n_writers = 3; + const MSG: &str = "Hello, World"; + + for _ in 0..n_tries { + let cell: OnceCell = OnceCell::new(); + scope(|scope| { + for _ in 0..n_readers { + scope.spawn(|_| loop { + if let Some(msg) = cell.get() { + assert_eq!(msg, MSG); + break; + } + }); + } + for _ in 0..n_writers { + let _ = scope.spawn(|_| cell.set(MSG.to_owned())); + } + }) + .unwrap() + } + } + + #[cfg(feature = "std")] + #[test] + fn get_does_not_block() { + let cell = OnceCell::new(); + let barrier = Barrier::new(2); + scope(|scope| { + scope.spawn(|_| { + cell.get_or_init(|| { + barrier.wait(); + barrier.wait(); + "hello".to_string() + }); + }); + barrier.wait(); + assert_eq!(cell.get(), None); + barrier.wait(); + }) + .unwrap(); + assert_eq!(cell.get(), Some(&"hello".to_string())); + } + + #[test] + // https://github.com/rust-lang/rust/issues/34761#issuecomment-256320669 + fn arrrrrrrrrrrrrrrrrrrrrr() { + let cell = OnceCell::new(); + { + let s = String::new(); + cell.set(&s).unwrap(); + } + } +} + +#[cfg(feature = "race")] +mod race { + #[cfg(feature = "std")] + use std::sync::Barrier; + use std::{ + num::NonZeroUsize, + sync::atomic::{AtomicUsize, Ordering::SeqCst}, + }; + + use crossbeam_utils::thread::scope; + + use once_cell::race::{OnceBool, OnceNonZeroUsize}; + + #[test] + fn once_non_zero_usize_smoke_test() { + let cnt = AtomicUsize::new(0); + let cell = OnceNonZeroUsize::new(); + let val = NonZeroUsize::new(92).unwrap(); + scope(|s| { + s.spawn(|_| { + assert_eq!( + cell.get_or_init(|| { + cnt.fetch_add(1, SeqCst); + val + }), + val + ); + assert_eq!(cnt.load(SeqCst), 1); + + assert_eq!( + cell.get_or_init(|| { + cnt.fetch_add(1, SeqCst); + val + }), + val + ); + assert_eq!(cnt.load(SeqCst), 1); + }); + }) + .unwrap(); + assert_eq!(cell.get(), Some(val)); + assert_eq!(cnt.load(SeqCst), 1); + } + + #[test] + fn once_non_zero_usize_set() { + let val1 = NonZeroUsize::new(92).unwrap(); + let val2 = NonZeroUsize::new(62).unwrap(); + + let cell = OnceNonZeroUsize::new(); + + assert!(cell.set(val1).is_ok()); + assert_eq!(cell.get(), Some(val1)); + + assert!(cell.set(val2).is_err()); + assert_eq!(cell.get(), Some(val1)); + } + + #[cfg(feature = "std")] + #[test] + fn once_non_zero_usize_first_wins() { + let val1 = NonZeroUsize::new(92).unwrap(); + let val2 = NonZeroUsize::new(62).unwrap(); + + let cell = OnceNonZeroUsize::new(); + + let b1 = Barrier::new(2); + let b2 = Barrier::new(2); + let b3 = Barrier::new(2); + scope(|s| { + s.spawn(|_| { + let r1 = cell.get_or_init(|| { + b1.wait(); + b2.wait(); + val1 + }); + assert_eq!(r1, val1); + b3.wait(); + }); + b1.wait(); + s.spawn(|_| { + let r2 = cell.get_or_init(|| { + b2.wait(); + b3.wait(); + val2 + }); + assert_eq!(r2, val1); + }); + }) + .unwrap(); + + assert_eq!(cell.get(), Some(val1)); + } + + #[test] + fn once_bool_smoke_test() { + let cnt = AtomicUsize::new(0); + let cell = OnceBool::new(); + scope(|s| { + s.spawn(|_| { + assert_eq!( + cell.get_or_init(|| { + cnt.fetch_add(1, SeqCst); + false + }), + false + ); + assert_eq!(cnt.load(SeqCst), 1); + + assert_eq!( + cell.get_or_init(|| { + cnt.fetch_add(1, SeqCst); + false + }), + false + ); + assert_eq!(cnt.load(SeqCst), 1); + }); + }) + .unwrap(); + assert_eq!(cell.get(), Some(false)); + assert_eq!(cnt.load(SeqCst), 1); + } + + #[test] + fn once_bool_set() { + let cell = OnceBool::new(); + + assert!(cell.set(false).is_ok()); + assert_eq!(cell.get(), Some(false)); + + assert!(cell.set(true).is_err()); + assert_eq!(cell.get(), Some(false)); + } +} + +#[cfg(all(feature = "race", feature = "alloc"))] +mod race_once_box { + #[cfg(feature = "std")] + use std::sync::Barrier; + use std::sync::{ + atomic::{AtomicUsize, Ordering::SeqCst}, + Arc, + }; + + #[cfg(feature = "std")] + use crossbeam_utils::thread::scope; + + use once_cell::race::OnceBox; + + #[derive(Default)] + struct Heap { + total: Arc, + } + + #[derive(Debug)] + struct Pebble { + val: T, + total: Arc, + } + + impl Drop for Pebble { + fn drop(&mut self) { + self.total.fetch_sub(1, SeqCst); + } + } + + impl Heap { + fn total(&self) -> usize { + self.total.load(SeqCst) + } + fn new_pebble(&self, val: T) -> Pebble { + self.total.fetch_add(1, SeqCst); + Pebble { val, total: Arc::clone(&self.total) } + } + } + + #[cfg(feature = "std")] + #[test] + fn once_box_smoke_test() { + let heap = Heap::default(); + let global_cnt = AtomicUsize::new(0); + let cell = OnceBox::new(); + let b = Barrier::new(128); + scope(|s| { + for _ in 0..128 { + s.spawn(|_| { + let local_cnt = AtomicUsize::new(0); + cell.get_or_init(|| { + global_cnt.fetch_add(1, SeqCst); + local_cnt.fetch_add(1, SeqCst); + b.wait(); + Box::new(heap.new_pebble(())) + }); + assert_eq!(local_cnt.load(SeqCst), 1); + + cell.get_or_init(|| { + global_cnt.fetch_add(1, SeqCst); + local_cnt.fetch_add(1, SeqCst); + Box::new(heap.new_pebble(())) + }); + assert_eq!(local_cnt.load(SeqCst), 1); + }); + } + }) + .unwrap(); + assert!(cell.get().is_some()); + assert!(global_cnt.load(SeqCst) > 10); + + assert_eq!(heap.total(), 1); + drop(cell); + assert_eq!(heap.total(), 0); + } + + #[test] + fn once_box_set() { + let heap = Heap::default(); + let cell = OnceBox::new(); + assert!(cell.get().is_none()); + + assert!(cell.set(Box::new(heap.new_pebble("hello"))).is_ok()); + assert_eq!(cell.get().unwrap().val, "hello"); + assert_eq!(heap.total(), 1); + + assert!(cell.set(Box::new(heap.new_pebble("world"))).is_err()); + assert_eq!(cell.get().unwrap().val, "hello"); + assert_eq!(heap.total(), 1); + + drop(cell); + assert_eq!(heap.total(), 0); + } + + #[cfg(feature = "std")] + #[test] + fn once_box_first_wins() { + let cell = OnceBox::new(); + let val1 = 92; + let val2 = 62; + + let b1 = Barrier::new(2); + let b2 = Barrier::new(2); + let b3 = Barrier::new(2); + scope(|s| { + s.spawn(|_| { + let r1 = cell.get_or_init(|| { + b1.wait(); + b2.wait(); + Box::new(val1) + }); + assert_eq!(*r1, val1); + b3.wait(); + }); + b1.wait(); + s.spawn(|_| { + let r2 = cell.get_or_init(|| { + b2.wait(); + b3.wait(); + Box::new(val2) + }); + assert_eq!(*r2, val1); + }); + }) + .unwrap(); + + assert_eq!(cell.get(), Some(&val1)); + } + + #[test] + fn once_box_reentrant() { + let cell = OnceBox::new(); + let res = cell.get_or_init(|| { + cell.get_or_init(|| Box::new("hello".to_string())); + Box::new("world".to_string()) + }); + assert_eq!(res, "hello"); + } + + #[test] + fn once_box_default() { + struct Foo; + + let cell: OnceBox = Default::default(); + assert!(cell.get().is_none()); + } +} diff --git a/third_party/rust/proc_macro_crate/v1/BUILD.gn b/third_party/rust/proc_macro_crate/v1/BUILD.gn index 7171186583b6..8577f48fe055 100644 --- a/third_party/rust/proc_macro_crate/v1/BUILD.gn +++ b/third_party/rust/proc_macro_crate/v1/BUILD.gn @@ -30,6 +30,6 @@ cargo_crate("lib") { executable_configs += [ "//build/config/compiler:no_chromium_code" ] deps = [ "//brave/third_party/rust/thiserror/v1:lib", - "//third_party/rust/toml/v0_5:lib", + "//brave/third_party/rust/toml/v0_5:lib", ] } diff --git a/third_party/rust/string_cache/v0_8/BUILD.gn b/third_party/rust/string_cache/v0_8/BUILD.gn index 1ec7c453f5af..de855b192b8b 100644 --- a/third_party/rust/string_cache/v0_8/BUILD.gn +++ b/third_party/rust/string_cache/v0_8/BUILD.gn @@ -37,10 +37,10 @@ cargo_crate("lib") { executable_configs += [ "//build/config/compiler:no_chromium_code" ] deps = [ "//brave/third_party/rust/new_debug_unreachable/v1:lib", + "//brave/third_party/rust/once_cell/v1:lib", "//brave/third_party/rust/parking_lot/v0_12:lib", "//brave/third_party/rust/phf_shared/v0_10:lib", "//brave/third_party/rust/precomputed_hash/v0_1:lib", - "//third_party/rust/once_cell/v1:lib", "//third_party/rust/serde/v1:lib", ] aliased_deps = { diff --git a/third_party/rust/thread_local/v1/BUILD.gn b/third_party/rust/thread_local/v1/BUILD.gn index ba0c74361bd1..5cfdc160e343 100644 --- a/third_party/rust/thread_local/v1/BUILD.gn +++ b/third_party/rust/thread_local/v1/BUILD.gn @@ -34,7 +34,7 @@ cargo_crate("lib") { executable_configs -= [ "//build/config/compiler:chromium_code" ] executable_configs += [ "//build/config/compiler:no_chromium_code" ] deps = [ + "//brave/third_party/rust/once_cell/v1:lib", "//third_party/rust/cfg_if/v1:lib", - "//third_party/rust/once_cell/v1:lib", ] } diff --git a/third_party/rust/toml/v0_5/BUILD.gn b/third_party/rust/toml/v0_5/BUILD.gn new file mode 100644 index 000000000000..d302fb9d0bb0 --- /dev/null +++ b/third_party/rust/toml/v0_5/BUILD.gn @@ -0,0 +1,59 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# @generated from third_party/rust/BUILD.gn.hbs by tools/crates/gnrt. +# Do not edit! + +import("//build/rust/cargo_crate.gni") + +cargo_crate("lib") { + crate_name = "toml" + epoch = "0.5" + crate_type = "rlib" + + # Only for usage from third-party crates. Add the crate to + # third_party.toml to use it from first-party code. + visibility = [ "//brave/third_party/rust/*" ] + crate_root = "crate/src/lib.rs" + sources = [ + "//brave/third_party/rust/toml/v0_5/crate/examples/decode.rs", + "//brave/third_party/rust/toml/v0_5/crate/examples/enum_external.rs", + "//brave/third_party/rust/toml/v0_5/crate/examples/toml2json.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/datetime.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/de.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/lib.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/macros.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/map.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/ser.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/spanned.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/tokens.rs", + "//brave/third_party/rust/toml/v0_5/crate/src/value.rs", + "//brave/third_party/rust/toml/v0_5/crate/tests/enum_external_deserialize.rs", + ] + inputs = [ "//brave/third_party/rust/toml/v0_5/crate/README.md" ] + + # Unit tests skipped. Generate with --with-tests to include them. + build_native_rust_unit_tests = false + edition = "2018" + cargo_pkg_version = "0.5.9" + cargo_pkg_authors = "Alex Crichton " + cargo_pkg_name = "toml" + cargo_pkg_description = "A native Rust encoder and decoder of TOML-formatted files and streams. Provides implementations of the standard Serialize/Deserialize traits for TOML data to facilitate deserializing and serializing Rust structures." + library_configs -= [ "//build/config/compiler:chromium_code" ] + library_configs += [ "//build/config/compiler:no_chromium_code" ] + executable_configs -= [ "//build/config/compiler:chromium_code" ] + executable_configs += [ "//build/config/compiler:no_chromium_code" ] + deps = [ + "//brave/third_party/rust/indexmap/v1:lib", + "//third_party/rust/serde/v1:lib", + ] + features = [ + "indexmap", + "preserve_order", + ] +} +group("test_support") { + public_deps = [ ":lib" ] + testonly = true +} diff --git a/third_party/rust/toml/v0_5/README.chromium b/third_party/rust/toml/v0_5/README.chromium new file mode 100644 index 000000000000..4e153e67ff65 --- /dev/null +++ b/third_party/rust/toml/v0_5/README.chromium @@ -0,0 +1,9 @@ +Name: toml +URL: https://crates.io/crates/toml +Description: A native Rust encoder and decoder of TOML-formatted files and streams. Provides +implementations of the standard Serialize/Deserialize traits for TOML data to +facilitate deserializing and serializing Rust structures. +Version: 0.5.9 +Security Critical: no +Shipped: no +License: Apache 2.0 diff --git a/third_party/rust/toml/v0_5/crate/.cargo_vcs_info.json b/third_party/rust/toml/v0_5/crate/.cargo_vcs_info.json new file mode 100644 index 000000000000..69ea9b4ba0cc --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "70caf4085324bff452d8c20ead55974513030696" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/rust/toml/v0_5/crate/.github/dependabot.yml b/third_party/rust/toml/v0_5/crate/.github/dependabot.yml new file mode 100644 index 000000000000..7377d37597f7 --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + time: "08:00" + open-pull-requests-limit: 10 diff --git a/third_party/rust/toml/v0_5/crate/.github/workflows/main.yml b/third_party/rust/toml/v0_5/crate/.github/workflows/main.yml new file mode 100644 index 000000000000..c6fa6e992d4e --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/.github/workflows/main.yml @@ -0,0 +1,45 @@ +name: CI +on: [push, pull_request] + +jobs: + test: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + rust: [stable, beta, nightly] + steps: + - uses: actions/checkout@master + - name: Install Rust (rustup) + run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} + - run: cargo test + - run: cargo test --features preserve_order + - run: cargo test --manifest-path test-suite/Cargo.toml + - run: cargo bench + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check + + publish_docs: + name: Publish Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable + - name: Build documentation + run: cargo doc --no-deps --all-features + - name: Publish documentation + run: | + cd target/doc + git init + git add . + git -c user.name='ci' -c user.email='ci' commit -m init + git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} HEAD:gh-pages + if: github.event_name == 'push' && github.event.ref == 'refs/heads/master' diff --git a/third_party/rust/toml/v0_5/crate/.gitignore b/third_party/rust/toml/v0_5/crate/.gitignore new file mode 100644 index 000000000000..a9d37c560c6a --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/third_party/rust/toml/v0_5/crate/Cargo.toml b/third_party/rust/toml/v0_5/crate/Cargo.toml new file mode 100644 index 000000000000..2e30a900a8fa --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "toml" +version = "0.5.9" +authors = ["Alex Crichton "] +description = """ +A native Rust encoder and decoder of TOML-formatted files and streams. Provides +implementations of the standard Serialize/Deserialize traits for TOML data to +facilitate deserializing and serializing Rust structures. +""" +homepage = "https://github.com/alexcrichton/toml-rs" +documentation = "https://docs.rs/toml" +readme = "README.md" +keywords = ["encoding"] +categories = [ + "config", + "encoding", + "parser-implementations", +] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/toml-rs" + +[dependencies.indexmap] +version = "1.0" +optional = true + +[dependencies.serde] +version = "1.0.97" + +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.serde_json] +version = "1.0" + +[features] +default = [] +preserve_order = ["indexmap"] diff --git a/third_party/rust/toml/v0_5/crate/Cargo.toml.orig b/third_party/rust/toml/v0_5/crate/Cargo.toml.orig new file mode 100644 index 000000000000..f87580283f95 --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/Cargo.toml.orig @@ -0,0 +1,36 @@ +[package] +name = "toml" +version = "0.5.9" +authors = ["Alex Crichton "] +license = "MIT/Apache-2.0" +readme = "README.md" +keywords = ["encoding"] +repository = "https://github.com/alexcrichton/toml-rs" +homepage = "https://github.com/alexcrichton/toml-rs" +documentation = "https://docs.rs/toml" +description = """ +A native Rust encoder and decoder of TOML-formatted files and streams. Provides +implementations of the standard Serialize/Deserialize traits for TOML data to +facilitate deserializing and serializing Rust structures. +""" +categories = ["config", "encoding", "parser-implementations"] +edition = "2018" + +[workspace] +members = ['test-suite'] + +[dependencies] +serde = "1.0.97" +indexmap = { version = "1.0", optional = true } + +[dev-dependencies] +serde_derive = "1.0" +serde_json = "1.0" + +[features] +default = [] + +# Use indexmap rather than BTreeMap as the map type of toml::Value. +# This allows data to be read into a Value and written back to a TOML string +# while preserving the order of map keys in the input. +preserve_order = ["indexmap"] diff --git a/third_party/rust/toml/v0_5/crate/LICENSE-APACHE b/third_party/rust/toml/v0_5/crate/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/toml/v0_5/crate/LICENSE-MIT b/third_party/rust/toml/v0_5/crate/LICENSE-MIT new file mode 100644 index 000000000000..39e0ed660215 --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/toml/v0_5/crate/README.md b/third_party/rust/toml/v0_5/crate/README.md new file mode 100644 index 000000000000..21dd1088a20b --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/README.md @@ -0,0 +1,38 @@ +# toml-rs + +[![Latest Version](https://img.shields.io/crates/v/toml.svg)](https://crates.io/crates/toml) +[![Documentation](https://docs.rs/toml/badge.svg)](https://docs.rs/toml) + +A [TOML][toml] decoder and encoder for Rust. This library is currently compliant +with the v0.5.0 version of TOML. This library will also likely continue to stay +up to date with the TOML specification as changes happen. + +[toml]: https://github.com/toml-lang/toml + +```toml +# Cargo.toml +[dependencies] +toml = "0.5" +``` + +This crate also supports serialization/deserialization through the +[serde](https://serde.rs) crate on crates.io. Currently the older `rustc-serialize` +crate is not supported in the 0.3+ series of the `toml` crate, but 0.2 can be +used for that support. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in toml-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/third_party/rust/toml/v0_5/crate/examples/decode.rs b/third_party/rust/toml/v0_5/crate/examples/decode.rs new file mode 100644 index 000000000000..256069b350c5 --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/examples/decode.rs @@ -0,0 +1,54 @@ +//! An example showing off the usage of `Deserialize` to automatically decode +//! TOML into a Rust `struct` + +#![deny(warnings)] +#![allow(dead_code)] + +use serde_derive::Deserialize; + +/// This is what we're going to decode into. Each field is optional, meaning +/// that it doesn't have to be present in TOML. +#[derive(Debug, Deserialize)] +struct Config { + global_string: Option, + global_integer: Option, + server: Option, + peers: Option>, +} + +/// Sub-structs are decoded from tables, so this will decode from the `[server]` +/// table. +/// +/// Again, each field is optional, meaning they don't have to be present. +#[derive(Debug, Deserialize)] +struct ServerConfig { + ip: Option, + port: Option, +} + +#[derive(Debug, Deserialize)] +struct PeerConfig { + ip: Option, + port: Option, +} + +fn main() { + let toml_str = r#" + global_string = "test" + global_integer = 5 + + [server] + ip = "127.0.0.1" + port = 80 + + [[peers]] + ip = "127.0.0.1" + port = 8080 + + [[peers]] + ip = "127.0.0.1" + "#; + + let decoded: Config = toml::from_str(toml_str).unwrap(); + println!("{:#?}", decoded); +} diff --git a/third_party/rust/toml/v0_5/crate/examples/enum_external.rs b/third_party/rust/toml/v0_5/crate/examples/enum_external.rs new file mode 100644 index 000000000000..7de061f61476 --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/examples/enum_external.rs @@ -0,0 +1,45 @@ +//! An example showing off the usage of `Deserialize` to automatically decode +//! TOML into a Rust `struct`, with enums. + +#![deny(warnings)] +#![allow(dead_code)] + +use serde_derive::Deserialize; + +/// This is what we're going to decode into. +#[derive(Debug, Deserialize)] +struct Config { + plain: MyEnum, + plain_table: MyEnum, + tuple: MyEnum, + #[serde(rename = "struct")] + structv: MyEnum, + newtype: MyEnum, + my_enum: Vec, +} + +#[derive(Debug, Deserialize)] +enum MyEnum { + Plain, + Tuple(i64, bool), + NewType(String), + Struct { value: i64 }, +} + +fn main() { + let toml_str = r#" + plain = "Plain" + plain_table = { Plain = {} } + tuple = { Tuple = { 0 = 123, 1 = true } } + struct = { Struct = { value = 123 } } + newtype = { NewType = "value" } + my_enum = [ + { Plain = {} }, + { Tuple = { 0 = 123, 1 = true } }, + { NewType = "value" }, + { Struct = { value = 123 } } + ]"#; + + let decoded: Config = toml::from_str(toml_str).unwrap(); + println!("{:#?}", decoded); +} diff --git a/third_party/rust/toml/v0_5/crate/examples/toml2json.rs b/third_party/rust/toml/v0_5/crate/examples/toml2json.rs new file mode 100644 index 000000000000..1b90c9fde59a --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/examples/toml2json.rs @@ -0,0 +1,47 @@ +#![deny(warnings)] + +use std::env; +use std::fs::File; +use std::io; +use std::io::prelude::*; + +use serde_json::Value as Json; +use toml::Value as Toml; + +fn main() { + let mut args = env::args(); + let mut input = String::new(); + if args.len() > 1 { + let name = args.nth(1).unwrap(); + File::open(&name) + .and_then(|mut f| f.read_to_string(&mut input)) + .unwrap(); + } else { + io::stdin().read_to_string(&mut input).unwrap(); + } + + match input.parse() { + Ok(toml) => { + let json = convert(toml); + println!("{}", serde_json::to_string_pretty(&json).unwrap()); + } + Err(error) => println!("failed to parse TOML: {}", error), + } +} + +fn convert(toml: Toml) -> Json { + match toml { + Toml::String(s) => Json::String(s), + Toml::Integer(i) => Json::Number(i.into()), + Toml::Float(f) => { + let n = serde_json::Number::from_f64(f).expect("float infinite and nan not allowed"); + Json::Number(n) + } + Toml::Boolean(b) => Json::Bool(b), + Toml::Array(arr) => Json::Array(arr.into_iter().map(convert).collect()), + Toml::Table(table) => { + Json::Object(table.into_iter().map(|(k, v)| (k, convert(v))).collect()) + } + Toml::Datetime(dt) => Json::String(dt.to_string()), + } +} diff --git a/third_party/rust/toml/v0_5/crate/src/datetime.rs b/third_party/rust/toml/v0_5/crate/src/datetime.rs new file mode 100644 index 000000000000..a68b0756836d --- /dev/null +++ b/third_party/rust/toml/v0_5/crate/src/datetime.rs @@ -0,0 +1,544 @@ +use std::error; +use std::fmt; +use std::str::{self, FromStr}; + +use serde::{de, ser}; + +/// A parsed TOML datetime value +/// +/// This structure is intended to represent the datetime primitive type that can +/// be encoded into TOML documents. This type is a parsed version that contains +/// all metadata internally. +/// +/// Currently this type is intentionally conservative and only supports +/// `to_string` as an accessor. Over time though it's intended that it'll grow +/// more support! +/// +/// Note that if you're using `Deserialize` to deserialize a TOML document, you +/// can use this as a placeholder for where you're expecting a datetime to be +/// specified. +/// +/// Also note though that while this type implements `Serialize` and +/// `Deserialize` it's only recommended to use this type with the TOML format, +/// otherwise encoded in other formats it may look a little odd. +/// +/// Depending on how the option values are used, this struct will correspond +/// with one of the following four datetimes from the [TOML v1.0.0 spec]: +/// +/// | `date` | `time` | `offset` | TOML type | +/// | --------- | --------- | --------- | ------------------ | +/// | `Some(_)` | `Some(_)` | `Some(_)` | [Offset Date-Time] | +/// | `Some(_)` | `Some(_)` | `None` | [Local Date-Time] | +/// | `Some(_)` | `None` | `None` | [Local Date] | +/// | `None` | `Some(_)` | `None` | [Local Time] | +/// +/// **1. Offset Date-Time**: If all the optional values are used, `Datetime` +/// corresponds to an [Offset Date-Time]. From the TOML v1.0.0 spec: +/// +/// > To unambiguously represent a specific instant in time, you may use an +/// > RFC 3339 formatted date-time with offset. +/// > +/// > ```toml +/// > odt1 = 1979-05-27T07:32:00Z +/// > odt2 = 1979-05-27T00:32:00-07:00 +/// > odt3 = 1979-05-27T00:32:00.999999-07:00 +/// > ``` +/// > +/// > For the sake of readability, you may replace the T delimiter between date +/// > and time with a space character (as permitted by RFC 3339 section 5.6). +/// > +/// > ```toml +/// > odt4 = 1979-05-27 07:32:00Z +/// > ``` +/// +/// **2. Local Date-Time**: If `date` and `time` are given but `offset` is +/// `None`, `Datetime` corresponds to a [Local Date-Time]. From the spec: +/// +/// > If you omit the offset from an RFC 3339 formatted date-time, it will +/// > represent the given date-time without any relation to an offset or +/// > timezone. It cannot be converted to an instant in time without additional +/// > information. Conversion to an instant, if required, is implementation- +/// > specific. +/// > +/// > ```toml +/// > ldt1 = 1979-05-27T07:32:00 +/// > ldt2 = 1979-05-27T00:32:00.999999 +/// > ``` +/// +/// **3. Local Date**: If only `date` is given, `Datetime` corresponds to a +/// [Local Date]; see the docs for [`Date`]. +/// +/// **4. Local Time**: If only `time` is given, `Datetime` corresponds to a +/// [Local Time]; see the docs for [`Time`]. +/// +/// [TOML v1.0.0 spec]: https://toml.io/en/v1.0.0 +/// [Offset Date-Time]: https://toml.io/en/v1.0.0#offset-date-time +/// [Local Date-Time]: https://toml.io/en/v1.0.0#local-date-time +/// [Local Date]: https://toml.io/en/v1.0.0#local-date +/// [Local Time]: https://toml.io/en/v1.0.0#local-time +#[derive(PartialEq, Clone)] +pub struct Datetime { + /// Optional date. + /// Required for: *Offset Date-Time*, *Local Date-Time*, *Local Date*. + pub date: Option, + + /// Optional time. + /// Required for: *Offset Date-Time*, *Local Date-Time*, *Local Time*. + pub time: Option