+// umtx_initOnce variant for plain functions, or static class functions,
+// with a context parameter.
+template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
+ if (umtx_loadAcquire(uio.fState) == 2) {
+ return;
+ }
+ if (umtx_initImplPreInit(uio)) {
+ (*fp)(context);
+ umtx_initImplPostInit(uio);
+ }
+}
+
+// umtx_initOnce variant for plain functions, or static class functions,
+// with a context parameter and an error code.
+template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
+ if (U_FAILURE(errCode)) {
+ return;
+ }
+ if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
+ // We run the initialization.
+ (*fp)(context, errCode);
+ uio.fErrCode = errCode;
+ umtx_initImplPostInit(uio);
+ } else {
+ // Someone else already ran the initialization.
+ if (U_FAILURE(uio.fErrCode)) {
+ errCode = uio.fErrCode;
+ }
+ }
+}
+
+
+/**
+ * ICU Mutex wrappers. Originally wrapped operating system mutexes, giving the rest of ICU a
+ * platform independent set of mutex operations. Now vestigial, wrapping std::mutex only.
+ * For internal ICU use only.
+ *
+ * Caution: do not directly declare static or global instances of UMutex. Doing so can introduce
+ * static initializers, which are disallowed in ICU library code. Instead, use the following
+ * idiom, which avoids static init and also avoids ordering issues on destruction
+ * (use after delete) by avoiding destruction altogether.
+ *
+ * UMutex *myMutex() {
+ * static UMutex *m = STATIC_NEW(UMutex);
+ * return m;
+ * }
+ * ...
+ *
+ * Mutex lock(myMutex()); // hold myMutex until the variable "lock" goes out of scope.
+ */
+
+struct UMutex : public icu::UMemory {
+ UMutex() = default;
+ ~UMutex() = default;
+ UMutex(const UMutex &other) = delete;
+ UMutex &operator =(const UMutex &other) = delete;
+
+ std::mutex fMutex = {}; // Note: struct - pubic members - because most access is from
+ // // plain C style functions (umtx_lock(), etc.)
+};