diff --git a/.gitignore b/.gitignore
index 0edccb51a..07d5499b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,10 @@
build
*output/
+paddlespeech/audio/_paddleaudio.so
+paddlespeech/audio/lib/libpaddleaudio.so
+paddlespeech/version.py
+
docs/build/
docs/topic/ctc/warp-ctc/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2906f9180..d60ca758e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,17 +1,46 @@
-cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Use compiler ID "AppleClang" instead of "Clang" for XCode.
+# Not setting this sometimes makes XCode C compiler gets detected as "Clang",
+# even when the C++ one is detected as "AppleClang".
+cmake_policy(SET CMP0010 NEW)
+cmake_policy(SET CMP0025 NEW)
+
+# Suppress warning flags in default MSVC configuration. It's not
+# mandatory that we do this (and we don't if cmake is old), but it's
+# nice when it's possible, and it's possible on our Windows configs.
+if(NOT CMAKE_VERSION VERSION_LESS 3.15.0)
+ cmake_policy(SET CMP0092 NEW)
+endif()
project(paddlespeech)
# check and set CMAKE_CXX_STANDARD
string(FIND "${CMAKE_CXX_FLAGS}" "-std=c++" env_cxx_standard)
+if(env_cxx_standard GREATER -1)
+ message(
+ WARNING "C++ standard version definition detected in environment variable."
+ "paddlespeech requires -std=c++14. Please remove -std=c++ settings in your environment.")
+endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_C_STANDARD 11)
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
# Options
option(BUILD_SOX "Build libsox statically" ON)
+option(BUILD_MAD "Enable libmad" ON)
+option(BUILD_PADDLEAUDIO_PYTHON_EXTENSION "Build Python extension" ON)
+
+set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+find_package(Python3 COMPONENTS Interpreter Development)
+find_package(pybind11 CONFIG)
+message(STATUS "Python_INCLUDE_DIR=" ${Python_INCLUDE_DIR})
add_subdirectory(paddlespeech/audio/third_party)
add_subdirectory(paddlespeech/audio/src)
diff --git a/paddlespeech/__init__.py b/paddlespeech/__init__.py
index b781c4a8e..4b1c0ef3d 100644
--- a/paddlespeech/__init__.py
+++ b/paddlespeech/__init__.py
@@ -14,3 +14,5 @@
import _locale
_locale._getdefaultlocale = (lambda *args: ['en_US', 'utf8'])
+
+
diff --git a/paddlespeech/audio/README.md b/paddlespeech/audio/README.md
index dd33bcf8b..aeb89ce40 100644
--- a/paddlespeech/audio/README.md
+++ b/paddlespeech/audio/README.md
@@ -3,7 +3,29 @@
## Reference
`csrc` code is reference of `torchaudio`.
+```text
BSD 2-Clause License
-Copyright (c) 2017 Facebook Inc. (Soumith Chintala),
-All rights reserved.
+Copyright (c) [year], [fullname]
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+```
\ No newline at end of file
diff --git a/paddlespeech/audio/__init__.py b/paddlespeech/audio/__init__.py
index 6184c1dd4..b84927f49 100644
--- a/paddlespeech/audio/__init__.py
+++ b/paddlespeech/audio/__init__.py
@@ -19,4 +19,4 @@ from . import io
from . import metric
from . import sox_effects
from .backends import load
-from .backends import save
+from .backends import save
\ No newline at end of file
diff --git a/paddlespeech/audio/_class.py b/paddlespeech/audio/_class.py
new file mode 100644
index 000000000..ed4c0116e
--- /dev/null
+++ b/paddlespeech/audio/_class.py
@@ -0,0 +1,47 @@
+import types
+
+class _ClassNamespace(types.ModuleType):
+ def __init__(self, name):
+ super(_ClassNamespace, self).__init__('paddlespeech.classes' + name)
+ self.name = name
+
+ def __getattr__(self, attr):
+ proxy = None
+ if proxy is None:
+ raise RuntimeError(f'Class {self.name}.{attr} not registered!')
+ return proxy
+
+class _Classes(types.ModuleType):
+ __file__ = '_classes.py'
+
+ def __init__(self):
+ super(_Classes, self).__init__('paddlespeech.classes')
+
+ def __getattr__(self, name):
+ namespace = _ClassNamespace(name)
+ setattr(self, name, namespace)
+ return namespace
+
+ @property
+ def loaded_libraries(self):
+ return paddlespeech.ops.loaded_libraries
+
+ def load_library(self, path):
+ """
+ Loads a shared library from the given path into the current process.
+ The library being loaded may run global initialization code to register
+ custom classes with the PyTorch JIT runtime. This allows dynamically
+ loading custom classes. For this, you should compile your class
+ and the static registration code into a shared library object, and then
+ call ``torch.classes.load_library('path/to/libcustom.so')`` to load the
+ shared object.
+ After the library is loaded, it is added to the
+ ``torch.classes.loaded_libraries`` attribute, a set that may be inspected
+ for the paths of all libraries loaded using this function.
+ Args:
+ path (str): A path to a shared library to load.
+ """
+ paddlespeech.ops.load_library(path)
+
+# The classes "namespace"
+classes = _Classes()
\ No newline at end of file
diff --git a/paddlespeech/audio/_extension.py b/paddlespeech/audio/_extension.py
new file mode 100644
index 000000000..b35b81b61
--- /dev/null
+++ b/paddlespeech/audio/_extension.py
@@ -0,0 +1,98 @@
+import os
+import warnings
+from pathlib import Path
+
+from ._internal import module_utils as _mod_utils # noqa: F401
+
+_LIB_DIR = Path(__file__) / "lib"
+
+
+def _get_lib_path(lib: str):
+ suffix = "pyd" if os.name == "nt" else "so"
+ path = _LIB_DIR / f"{lib}.{suffix}"
+ return path
+
+
+def _load_lib(lib: str) -> bool:
+ """Load extension module
+ Note:
+ In case `paddleaudio` is deployed with `pex` format, the library file
+ is not in a standard location.
+ In this case, we expect that `libpaddlleaudio` is available somewhere
+ in the search path of dynamic loading mechanism, so that importing
+ `_paddlleaudio` will have library loader find and load `libpaddlleaudio`.
+ This is the reason why the function should not raising an error when the library
+ file is not found.
+ Returns:
+ bool:
+ True if the library file is found AND the library loaded without failure.
+ False if the library file is not found (like in the case where paddlleaudio
+ is deployed with pex format, thus the shared library file is
+ in a non-standard location.).
+ If the library file is found but there is an issue loading the library,
+ (such as missing dependency) then this function raises the exception as-is.
+ Raises:
+ Exception:
+ If the library file is found, but there is an issue loading the library file,
+ (when underlying `ctype.DLL` throws an exception), this function will pass
+ the exception as-is, instead of catching it and returning bool.
+ The expected case is `OSError` thrown by `ctype.DLL` when a dynamic dependency
+ is not found.
+ This behavior was chosen because the expected failure case is not recoverable.
+ If a dependency is missing, then users have to install it.
+ """
+ path = _get_lib_path(lib)
+ if not path.exists():
+ return False
+ paddlespeech.ops.load_library(path)
+ return True
+
+
+_FFMPEG_INITIALIZED = False
+
+
+def _init_ffmpeg():
+ global _FFMPEG_INITIALIZED
+ if _FFMPEG_INITIALIZED:
+ return
+
+ if not paddlespeech.ops.paddlleaudio.is_ffmpeg_available():
+ raise RuntimeError(
+ "paddlleaudio is not compiled with FFmpeg integration. Please set USE_FFMPEG=1 when compiling paddlleaudio."
+ )
+
+ try:
+ _load_lib("libpaddlleaudio_ffmpeg")
+ except OSError as err:
+ raise ImportError("FFmpeg libraries are not found. Please install FFmpeg.") from err
+
+ import paddllespeech._paddlleaudio_ffmpeg # noqa
+
+ paddlespeech.ops.paddlleaudio.ffmpeg_init()
+ if paddlespeech.ops.paddlleaudio.ffmpeg_get_log_level() > 8:
+ paddlespeech.ops.paddlleaudio.ffmpeg_set_log_level(8)
+
+ _FFMPEG_INITIALIZED = True
+
+
+def _init_extension():
+ if not _mod_utils.is_module_available("paddlespeech._paddleaudio"):
+ warnings.warn("paddlespeech C++ extension is not available.")
+ return
+
+ _load_lib("libpaddleaudio")
+ # This import is for initializing the methods registered via PyBind11
+ # This has to happen after the base library is loaded
+ from paddlespeech import _paddleaudio # noqa
+
+ # Because this part is executed as part of `import torchaudio`, we ignore the
+ # initialization failure.
+ # If the FFmpeg integration is not properly initialized, then detailed error
+ # will be raised when client code attempts to import the dedicated feature.
+ try:
+ _init_ffmpeg()
+ except Exception:
+ pass
+
+
+_init_extension()
\ No newline at end of file
diff --git a/paddlespeech/audio/_internal/__init__.py b/paddlespeech/audio/_internal/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/paddlespeech/audio/_internal/module_utils.py b/paddlespeech/audio/_internal/module_utils.py
new file mode 100644
index 000000000..cf6764262
--- /dev/null
+++ b/paddlespeech/audio/_internal/module_utils.py
@@ -0,0 +1,142 @@
+import importlib.util
+import warnings
+from functools import wraps
+from typing import Optional
+
+def is_module_available(*modules: str) -> bool:
+ r"""Returns if a top-level module with :attr:`name` exists *without**
+ importing it. This is generally safer than try-catch block around a
+ `import X`. It avoids third party libraries breaking assumptions of some of
+ our tests, e.g., setting multiprocessing start method when imported
+ (see librosa/#747, torchvision/#544).
+ """
+ return all(importlib.util.find_spec(m) is not None for m in modules)
+
+
+def requires_module(*modules: str):
+ """Decorate function to give error message if invoked without required optional modules.
+ This decorator is to give better error message to users rather
+ than raising ``NameError: name 'module' is not defined`` at random places.
+ """
+ missing = [m for m in modules if not is_module_available(m)]
+
+ if not missing:
+ # fall through. If all the modules are available, no need to decorate
+ def decorator(func):
+ return func
+
+ else:
+ req = f"module: {missing[0]}" if len(missing) == 1 else f"modules: {missing}"
+
+ def decorator(func):
+ @wraps(func)
+ def wrapped(*args, **kwargs):
+ raise RuntimeError(f"{func.__module__}.{func.__name__} requires {req}")
+
+ return wrapped
+
+ return decorator
+
+
+def deprecated(direction: str, version: Optional[str] = None):
+ """Decorator to add deprecation message
+ Args:
+ direction (str): Migration steps to be given to users.
+ version (str or int): The version when the object will be removed
+ """
+
+ def decorator(func):
+ @wraps(func)
+ def wrapped(*args, **kwargs):
+ message = (
+ f"{func.__module__}.{func.__name__} has been deprecated "
+ f'and will be removed from {"future" if version is None else version} release. '
+ f"{direction}"
+ )
+ warnings.warn(message, stacklevel=2)
+ return func(*args, **kwargs)
+
+ return wrapped
+
+ return decorator
+
+
+def is_kaldi_available():
+ return is_module_available("paddlespeech"._paddleaudio") and paddlespeech.ops.paddleaudio.is_kaldi_available()
+
+
+def requires_kaldi():
+ if is_kaldi_available():
+
+ def decorator(func):
+ return func
+
+ else:
+
+ def decorator(func):
+ @wraps(func)
+ def wrapped(*args, **kwargs):
+ raise RuntimeError(f"{func.__module__}.{func.__name__} requires kaldi")
+
+ return wrapped
+
+ return decorator
+
+
+def _check_soundfile_importable():
+ if not is_module_available("soundfile"):
+ return False
+ try:
+ import soundfile # noqa: F401
+
+ return True
+ except Exception:
+ warnings.warn("Failed to import soundfile. 'soundfile' backend is not available.")
+ return False
+
+
+_is_soundfile_importable = _check_soundfile_importable()
+
+
+def is_soundfile_available():
+ return _is_soundfile_importable
+
+
+def requires_soundfile():
+ if is_soundfile_available():
+
+ def decorator(func):
+ return func
+
+ else:
+
+ def decorator(func):
+ @wraps(func)
+ def wrapped(*args, **kwargs):
+ raise RuntimeError(f"{func.__module__}.{func.__name__} requires soundfile")
+
+ return wrapped
+
+ return decorator
+
+
+def is_sox_available():
+ return is_module_available("paddlespeech._paddleaudio") and paddlespeech.ops.paddleaudio.is_sox_available()
+
+
+def requires_sox():
+ if is_sox_available():
+
+ def decorator(func):
+ return func
+
+ else:
+
+ def decorator(func):
+ @wraps(func)
+ def wrapped(*args, **kwargs):
+ raise RuntimeError(f"{func.__module__}.{func.__name__} requires sox")
+
+ return wrapped
+
+ return
\ No newline at end of file
diff --git a/paddlespeech/audio/_ops.py b/paddlespeech/audio/_ops.py
new file mode 100644
index 000000000..0ef37592d
--- /dev/null
+++ b/paddlespeech/audio/_ops.py
@@ -0,0 +1,62 @@
+import contextlib
+import ctypes
+import sys
+import os
+import types
+
+# Query `hasattr` only once.
+_SET_GLOBAL_FLAGS = hasattr(sys, 'getdlopenflags') and hasattr(sys, 'setdlopenflags')
+
+
+@contextlib.contextmanager
+def dl_open_guard():
+ """
+ # https://manpages.debian.org/bullseye/manpages-dev/dlopen.3.en.html
+ Context manager to set the RTLD_GLOBAL dynamic linker flag while we open a
+ shared library to load custom operators.
+ """
+ if _SET_GLOBAL_FLAGS:
+ old_flags = sys.getdlopenflags()
+ sys.setdlopenflags(old_flags | ctypes.RTLD_GLOBAL)
+ yield
+ if _SET_GLOBAL_FLAGS:
+ sys.setdlopenflags(old_flags)
+
+
+def resolve_library_path(path: str) -> str:
+ return os.path.realpath(path)
+
+
+class _Ops(types.ModuleType):
+ __file__ = '_ops.py'
+
+ def __init__(self):
+ super(_Ops, self).__init__('paddlespeech.ops')
+ self.loaded_libraries = set()
+
+ def load_library(self, path):
+ """
+ Loads a shared library from the given path into the current process.
+ This allows dynamically loading custom operators. For this,
+ you should compile your operator and
+ the static registration code into a shared library object, and then
+ call ``paddlespeech.ops.load_library('path/to/libcustom.so')`` to load the
+ shared object.
+ After the library is loaded, it is added to the
+ ``paddlespeech.ops.loaded_libraries`` attribute, a set that may be inspected
+ for the paths of all libraries loaded using this function.
+ Args:
+ path (str): A path to a shared library to load.
+ """
+ path = resolve_library_path(path)
+ with dl_open_guard():
+ # https://docs.python.org/3/library/ctypes.html?highlight=ctypes#loading-shared-libraries
+ # Import the shared library into the process, thus running its
+ # static (global) initialization code in order to register custom
+ # operators with the JIT.
+ ctypes.CDLL(path)
+ self.loaded_libraries.add(path)
+
+
+# The ops "namespace"
+ops = _Ops()
\ No newline at end of file
diff --git a/paddlespeech/audio/lib/.gitignore b/paddlespeech/audio/lib/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/paddlespeech/audio/src/CMakeLists.txt b/paddlespeech/audio/src/CMakeLists.txt
index cbced3d02..e7b6892f7 100644
--- a/paddlespeech/audio/src/CMakeLists.txt
+++ b/paddlespeech/audio/src/CMakeLists.txt
@@ -1,36 +1,177 @@
-find_package(Python3 COMPONENTS Interpreter Development)
-find_package(pybind11 CONFIG)
+if (MSVC)
+ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+endif()
+
+################################################################################
+# libpaddleaudio
+################################################################################
+set(
+ LIBPADDLEAUDIO_SOURCES
+ utils.cpp
+ )
+
+set(
+ LIBPADDLEAUDIO_INCLUDE_DIRS
+ ${PROJECT_SOURCE_DIR}
+ )
+
+set(
+ LIBPADDLEAUDIO_LINK_LIBRARIES
+ )
+
+set(
+ LIBPADDLEAUDIO_COMPILE_DEFINITIONS)
-function(define_extension name sources libraries)
+#------------------------------------------------------------------------------#
+# START OF CUSTOMIZATION LOGICS
+#------------------------------------------------------------------------------#
+
+if(BUILD_SOX)
+ list(
+ APPEND
+ LIBPADDLEAUDIO_LINK_LIBRARIES
+ libsox
+ )
+ list(
+ APPEND
+ LIBPADDLEAUDIO_SOURCES
+ # sox/io.cpp
+ # sox/utils.cpp
+ # sox/effects.cpp
+ # sox/effects_chain.cpp
+ # sox/types.cpp
+ )
+ list(
+ APPEND
+ LIBPADDLEAUDIO_COMPILE_DEFINITIONS
+ INCLUDE_SOX
+ )
+endif()
+
+
+#------------------------------------------------------------------------------#
+# END OF CUSTOMIZATION LOGICS
+#------------------------------------------------------------------------------#
+
+function (define_library name source include_dirs link_libraries compile_defs)
+ add_library(${name} SHARED ${source})
+ target_include_directories(${name} PRIVATE ${include_dirs})
+ target_link_libraries(${name} ${link_libraries})
+ target_compile_definitions(${name} PRIVATE ${compile_defs})
+ set_target_properties(${name} PROPERTIES PREFIX "")
+ if (MSVC)
+ set_target_properties(${name} PROPERTIES SUFFIX ".pyd")
+ endif(MSVC)
+ install(
+ TARGETS ${name}
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION lib # For Windows
+ )
+endfunction()
+
+
+define_library(
+ libpaddleaudio
+ "${LIBPADDLEAUDIO_SOURCES}"
+ "${LIBPADDLEAUDIO_INCLUDE_DIRS}"
+ "${LIBPADDLEAUDIO_LINK_LIBRARIES}"
+ "${LIBPADDLEAUDIO_COMPILE_DEFINITIONS}"
+)
+
+if (APPLE)
+ set(TORCHAUDIO_LIBRARY libtorchaudio CACHE INTERNAL "")
+else()
+ set(TORCHAUDIO_LIBRARY -Wl,--no-as-needed libtorchaudio -Wl,--as-needed CACHE INTERNAL "")
+endif()
+
+ ################################################################################
+# _paddleaudio.so
+################################################################################
+if (BUILD_PADDLEAUDIO_PYTHON_EXTENSION)
+if (WIN32)
+ find_package(Python3 ${PYTHON_VERSION} EXACT COMPONENTS Development)
+ set(ADDITIONAL_ITEMS Python3::Python)
+endif()
+function(define_extension name sources include_dirs libraries definitions)
add_library(${name} SHARED ${sources})
+ target_compile_definitions(${name} PRIVATE "${definitions}")
target_include_directories(
- ${name} PRIVATE ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${Python3_INCLUDE_DIRS} ${pybind11_INCLUDE_DIR})
- target_link_libraries(${name} ${libraries})
+ ${name} PRIVATE ${PROJECT_SOURCE_DIR} ${Python_INCLUDE_DIR} ${include_dirs})
+ target_link_libraries(
+ ${name}
+ ${libraries}
+ ${TORCH_PYTHON_LIBRARY}
+ ${ADDITIONAL_ITEMS}
+ )
set_target_properties(${name} PROPERTIES PREFIX "")
+ if (MSVC)
+ set_target_properties(${name} PROPERTIES SUFFIX ".pyd")
+ endif(MSVC)
+ if (APPLE)
+ # https://github.com/facebookarchive/caffe2/issues/854#issuecomment-364538485
+ # https://github.com/pytorch/pytorch/commit/73f6715f4725a0723d8171d3131e09ac7abf0666
+ set_target_properties(${name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
+ endif()
install(
TARGETS ${name}
LIBRARY DESTINATION .
+ RUNTIME DESTINATION . # For Windows
)
endfunction()
+set(
+ EXTENSION_SOURCES
+ pybind/pybind.cpp
+ )
+#----------------------------------------------------------------------------#
+# START OF CUSTOMIZATION LOGICS
+#----------------------------------------------------------------------------#
if(BUILD_SOX)
- set(
+ list(
+ APPEND
EXTENSION_SOURCES
- pybind/pybind.cpp
+ # pybind/sox/effects.cpp
+ # pybind/sox/effects_chain.cpp
pybind/sox/io.cpp
pybind/sox/utils.cpp
)
-
- set(
- LINK_LIBRARIES
- libsox
- )
-
- define_extension(
- _paddleaudio
- "${EXTENSION_SOURCES}"
- "${LINK_LIBRARIES}"
- )
endif()
-
-add_subdirectory(pybind/kaldi_frontend)
+#----------------------------------------------------------------------------#
+# END OF CUSTOMIZATION LOGICS
+#----------------------------------------------------------------------------#
+define_extension(
+ _paddleaudio
+ "${EXTENSION_SOURCES}"
+ ""
+ libpaddleaudio
+ "${LIBPADDLEAUDIO_COMPILE_DEFINITIONS}"
+ )
+# if(BUILD_CTC_DECODER)
+# set(
+# DECODER_EXTENSION_SOURCES
+# decoder/bindings/pybind.cpp
+# )
+# define_extension(
+# _paddleaudio_decoder
+# "${DECODER_EXTENSION_SOURCES}"
+# ""
+# "libpaddleaudio_decoder"
+# "${LIBPADDLEAUDIO_DECODER_DEFINITIONS}"
+# )
+# endif()
+# if(USE_FFMPEG)
+# set(
+# FFMPEG_EXTENSION_SOURCES
+# ffmpeg/pybind/typedefs.cpp
+# ffmpeg/pybind/pybind.cpp
+# ffmpeg/pybind/stream_reader.cpp
+# )
+# define_extension(
+# _paddleaudio_ffmpeg
+# "${FFMPEG_EXTENSION_SOURCES}"
+# "${FFMPEG_INCLUDE_DIRS}"
+# "libpaddleaudio_ffmpeg"
+# "${LIBPADDLEAUDIO_DECODER_DEFINITIONS}"
+# )
+# endif()
+endif()
\ No newline at end of file
diff --git a/paddlespeech/audio/src/optional/COPYING b/paddlespeech/audio/src/optional/COPYING
new file mode 100644
index 000000000..0e259d42c
--- /dev/null
+++ b/paddlespeech/audio/src/optional/COPYING
@@ -0,0 +1,121 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
diff --git a/paddlespeech/audio/src/optional/optional.hpp b/paddlespeech/audio/src/optional/optional.hpp
new file mode 100644
index 000000000..9e5346f8d
--- /dev/null
+++ b/paddlespeech/audio/src/optional/optional.hpp
@@ -0,0 +1,2064 @@
+
+///
+// optional - An implementation of std::optional with extensions
+// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
+//
+// Documentation available at https://tl.tartanllama.xyz/
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this software to the
+// public domain worldwide. This software is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication
+// along with this software. If not, see
+// .
+// https://github.com/TartanLlama/optional
+///
+
+#ifndef TL_OPTIONAL_HPP
+#define TL_OPTIONAL_HPP
+
+#define TL_OPTIONAL_VERSION_MAJOR 1
+#define TL_OPTIONAL_VERSION_MINOR 0
+#define TL_OPTIONAL_VERSION_PATCH 0
+
+#include
+#include
+#include
+#include
+#include
+
+#if (defined(_MSC_VER) && _MSC_VER == 1900)
+#define TL_OPTIONAL_MSVC2015
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
+ !defined(__clang__))
+#define TL_OPTIONAL_GCC49
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
+ !defined(__clang__))
+#define TL_OPTIONAL_GCC54
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \
+ !defined(__clang__))
+#define TL_OPTIONAL_GCC55
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
+ !defined(__clang__))
+// GCC < 5 doesn't support overloading on const&& for member functions
+#define TL_OPTIONAL_NO_CONSTRR
+
+// GCC < 5 doesn't support some standard C++11 type traits
+#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ std::has_trivial_copy_constructor::value
+#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign::value
+
+// This one will be different for GCC 5.7 if it's ever supported
+#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
+
+// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector
+// for non-copyable types
+#elif (defined(__GNUC__) && __GNUC__ < 8 && \
+ !defined(__clang__))
+#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+namespace tl {
+ namespace detail {
+ template
+ struct is_trivially_copy_constructible : std::is_trivially_copy_constructible{};
+#ifdef _GLIBCXX_VECTOR
+ template
+ struct is_trivially_copy_constructible>
+ : std::is_trivially_copy_constructible{};
+#endif
+ }
+}
+#endif
+
+#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ tl::detail::is_trivially_copy_constructible::value
+#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+ std::is_trivially_copy_assignable::value
+#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
+#else
+#define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ std::is_trivially_copy_constructible::value
+#define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+ std::is_trivially_copy_assignable::value
+#define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
+#endif
+
+#if __cplusplus > 201103L
+#define TL_OPTIONAL_CXX14
+#endif
+
+// constexpr implies const in C++11, not C++14
+#if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \
+ defined(TL_OPTIONAL_GCC49))
+#define TL_OPTIONAL_11_CONSTEXPR
+#else
+#define TL_OPTIONAL_11_CONSTEXPR constexpr
+#endif
+
+namespace tl {
+#ifndef TL_MONOSTATE_INPLACE_MUTEX
+#define TL_MONOSTATE_INPLACE_MUTEX
+/// Used to represent an optional with no data; essentially a bool
+class monostate {};
+
+/// A tag type to tell optional to construct its value in-place
+struct in_place_t {
+ explicit in_place_t() = default;
+};
+/// A tag to tell optional to construct its value in-place
+static constexpr in_place_t in_place{};
+#endif
+
+template class optional;
+
+namespace detail {
+#ifndef TL_TRAITS_MUTEX
+#define TL_TRAITS_MUTEX
+// C++14-style aliases for brevity
+template using remove_const_t = typename std::remove_const::type;
+template
+using remove_reference_t = typename std::remove_reference::type;
+template using decay_t = typename std::decay::type;
+template
+using enable_if_t = typename std::enable_if::type;
+template
+using conditional_t = typename std::conditional::type;
+
+// std::conjunction from C++17
+template struct conjunction : std::true_type {};
+template struct conjunction : B {};
+template
+struct conjunction
+ : std::conditional, B>::type {};
+
+#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
+#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+#endif
+
+// In C++11 mode, there's an issue in libc++'s std::mem_fn
+// which results in a hard-error when using it in a noexcept expression
+// in some cases. This is a check to workaround the common failing case.
+#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
+template struct is_pointer_to_non_const_member_func : std::false_type{};
+template
+struct is_pointer_to_non_const_member_func : std::true_type{};
+template
+struct is_pointer_to_non_const_member_func : std::true_type{};
+template
+struct is_pointer_to_non_const_member_func : std::true_type{};
+template
+struct is_pointer_to_non_const_member_func : std::true_type{};
+template
+struct is_pointer_to_non_const_member_func : std::true_type{};
+template
+struct is_pointer_to_non_const_member_func : std::true_type{};
+
+template struct is_const_or_const_ref : std::false_type{};
+template struct is_const_or_const_ref : std::true_type{};
+template struct is_const_or_const_ref : std::true_type{};
+#endif
+
+// std::invoke from C++17
+// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
+template ::value
+ && is_const_or_const_ref::value)>,
+#endif
+ typename = enable_if_t>::value>,
+ int = 0>
+constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
+ noexcept(std::mem_fn(f)(std::forward(args)...)))
+ -> decltype(std::mem_fn(f)(std::forward(args)...)) {
+ return std::mem_fn(f)(std::forward(args)...);
+}
+
+template >::value>>
+constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
+ noexcept(std::forward(f)(std::forward(args)...)))
+ -> decltype(std::forward(f)(std::forward(args)...)) {
+ return std::forward(f)(std::forward(args)...);
+}
+
+// std::invoke_result from C++17
+template struct invoke_result_impl;
+
+template
+struct invoke_result_impl<
+ F, decltype(detail::invoke(std::declval(), std::declval()...), void()),
+ Us...> {
+ using type = decltype(detail::invoke(std::declval(), std::declval()...));
+};
+
+template
+using invoke_result = invoke_result_impl;
+
+template
+using invoke_result_t = typename invoke_result::type;
+
+#if defined(_MSC_VER) && _MSC_VER <= 1900
+// TODO make a version which works with MSVC 2015
+template struct is_swappable : std::true_type {};
+
+template struct is_nothrow_swappable : std::true_type {};
+#else
+// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
+namespace swap_adl_tests {
+// if swap ADL finds this then it would call std::swap otherwise (same
+// signature)
+struct tag {};
+
+template tag swap(T &, T &);
+template tag swap(T (&a)[N], T (&b)[N]);
+
+// helper functions to test if an unqualified swap is possible, and if it
+// becomes std::swap
+template std::false_type can_swap(...) noexcept(false);
+template (), std::declval()))>
+std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(),
+ std::declval())));
+
+template std::false_type uses_std(...);
+template
+std::is_same(), std::declval())), tag>
+uses_std(int);
+
+template
+struct is_std_swap_noexcept
+ : std::integral_constant::value &&
+ std::is_nothrow_move_assignable::value> {};
+
+template
+struct is_std_swap_noexcept : is_std_swap_noexcept {};
+
+template
+struct is_adl_swap_noexcept
+ : std::integral_constant(0))> {};
+} // namespace swap_adl_tests
+
+template
+struct is_swappable
+ : std::integral_constant<
+ bool,
+ decltype(detail::swap_adl_tests::can_swap(0))::value &&
+ (!decltype(detail::swap_adl_tests::uses_std(0))::value ||
+ (std::is_move_assignable::value &&
+ std::is_move_constructible::value))> {};
+
+template
+struct is_swappable
+ : std::integral_constant<
+ bool,
+ decltype(detail::swap_adl_tests::can_swap(0))::value &&
+ (!decltype(
+ detail::swap_adl_tests::uses_std(0))::value ||
+ is_swappable::value)> {};
+
+template
+struct is_nothrow_swappable
+ : std::integral_constant<
+ bool,
+ is_swappable::value &&
+ ((decltype(detail::swap_adl_tests::uses_std(0))::value
+ &&detail::swap_adl_tests::is_std_swap_noexcept::value) ||
+ (!decltype(detail::swap_adl_tests::uses_std(0))::value &&
+ detail::swap_adl_tests::is_adl_swap_noexcept::value))> {
+};
+#endif
+#endif
+
+// std::void_t from C++17
+template struct voider { using type = void; };
+template using void_t = typename voider::type;
+
+// Trait for checking if a type is a tl::optional
+template struct is_optional_impl : std::false_type {};
+template struct is_optional_impl> : std::true_type {};
+template using is_optional = is_optional_impl>;
+
+// Change void to tl::monostate
+template
+using fixup_void = conditional_t::value, monostate, U>;
+
+template >
+using get_map_return = optional>>;
+
+// Check if invoking F for some Us returns void
+template struct returns_void_impl;
+template
+struct returns_void_impl>, U...>
+ : std::is_void> {};
+template
+using returns_void = returns_void_impl;
+
+template
+using enable_if_ret_void = enable_if_t::value>;
+
+template
+using disable_if_ret_void = enable_if_t::value>;
+
+template
+using enable_forward_value =
+ detail::enable_if_t::value &&
+ !std::is_same, in_place_t>::value &&
+ !std::is_same, detail::decay_t>::value>;
+
+template
+using enable_from_other = detail::enable_if_t<
+ std::is_constructible::value &&
+ !std::is_constructible &>::value &&
+ !std::is_constructible &&>::value &&
+ !std::is_constructible &>::value &&
+ !std::is_constructible &&>::value &&
+ !std::is_convertible &, T>::value &&
+ !std::is_convertible &&, T>::value &&
+ !std::is_convertible &, T>::value &&
+ !std::is_convertible &&, T>::value>;
+
+template
+using enable_assign_forward = detail::enable_if_t<
+ !std::is_same, detail::decay_t>::value &&
+ !detail::conjunction,
+ std::is_same>>::value &&
+ std::is_constructible::value && std::is_assignable::value>;
+
+template
+using enable_assign_from_other = detail::enable_if_t<
+ std::is_constructible::value &&
+ std::is_assignable::value &&
+ !std::is_constructible &>::value &&
+ !std::is_constructible &&>::value &&
+ !std::is_constructible &>::value &&
+ !std::is_constructible &&>::value &&
+ !std::is_convertible &, T>::value &&
+ !std::is_convertible &&, T>::value &&
+ !std::is_convertible &, T>::value &&
+ !std::is_convertible &&, T>::value &&
+ !std::is_assignable &>::value &&
+ !std::is_assignable &&>::value &&
+ !std::is_assignable &>::value &&
+ !std::is_assignable &&>::value>;
+
+// The storage base manages the actual storage, and correctly propagates
+// trivial destruction from T. This case is for when T is not trivially
+// destructible.
+template ::value>
+struct optional_storage_base {
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
+ : m_dummy(), m_has_value(false) {}
+
+ template
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u)
+ : m_value(std::forward(u)...), m_has_value(true) {}
+
+ ~optional_storage_base() {
+ if (m_has_value) {
+ m_value.~T();
+ m_has_value = false;
+ }
+ }
+
+ struct dummy {};
+ union {
+ dummy m_dummy;
+ T m_value;
+ };
+
+ bool m_has_value;
+};
+
+// This case is for when T is trivially destructible.
+template struct optional_storage_base {
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
+ : m_dummy(), m_has_value(false) {}
+
+ template
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u)
+ : m_value(std::forward(u)...), m_has_value(true) {}
+
+ // No destructor, so this class is trivially destructible
+
+ struct dummy {};
+ union {
+ dummy m_dummy;
+ T m_value;
+ };
+
+ bool m_has_value = false;
+};
+
+// This base class provides some handy member functions which can be used in
+// further derived classes
+template struct optional_operations_base : optional_storage_base {
+ using optional_storage_base::optional_storage_base;
+
+ void hard_reset() noexcept {
+ get().~T();
+ this->m_has_value = false;
+ }
+
+ template void construct(Args &&... args) noexcept {
+ new (std::addressof(this->m_value)) T(std::forward(args)...);
+ this->m_has_value = true;
+ }
+
+ template void assign(Opt &&rhs) {
+ if (this->has_value()) {
+ if (rhs.has_value()) {
+ this->m_value = std::forward(rhs).get();
+ } else {
+ this->m_value.~T();
+ this->m_has_value = false;
+ }
+ }
+
+ else if (rhs.has_value()) {
+ construct(std::forward(rhs).get());
+ }
+ }
+
+ bool has_value() const { return this->m_has_value; }
+
+ TL_OPTIONAL_11_CONSTEXPR T &get() & { return this->m_value; }
+ TL_OPTIONAL_11_CONSTEXPR const T &get() const & { return this->m_value; }
+ TL_OPTIONAL_11_CONSTEXPR T &&get() && { return std::move(this->m_value); }
+#ifndef TL_OPTIONAL_NO_CONSTRR
+ constexpr const T &&get() const && { return std::move(this->m_value); }
+#endif
+};
+
+// This class manages conditionally having a trivial copy constructor
+// This specialization is for when T is trivially copy constructible
+template
+struct optional_copy_base : optional_operations_base {
+ using optional_operations_base::optional_operations_base;
+};
+
+// This specialization is for when T is not trivially copy constructible
+template
+struct optional_copy_base : optional_operations_base {
+ using optional_operations_base::optional_operations_base;
+
+ optional_copy_base() = default;
+ optional_copy_base(const optional_copy_base &rhs)
+ : optional_operations_base() {
+ if (rhs.has_value()) {
+ this->construct(rhs.get());
+ } else {
+ this->m_has_value = false;
+ }
+ }
+
+ optional_copy_base(optional_copy_base &&rhs) = default;
+ optional_copy_base &operator=(const optional_copy_base &rhs) = default;
+ optional_copy_base &operator=(optional_copy_base &&rhs) = default;
+};
+
+// This class manages conditionally having a trivial move constructor
+// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
+// doesn't implement an analogue to std::is_trivially_move_constructible. We
+// have to make do with a non-trivial move constructor even if T is trivially
+// move constructible
+#ifndef TL_OPTIONAL_GCC49
+template ::value>
+struct optional_move_base : optional_copy_base {
+ using optional_copy_base::optional_copy_base;
+};
+#else
+template struct optional_move_base;
+#endif
+template struct optional_move_base : optional_copy_base {
+ using optional_copy_base::optional_copy_base;
+
+ optional_move_base() = default;
+ optional_move_base(const optional_move_base &rhs) = default;
+
+ optional_move_base(optional_move_base &&rhs) noexcept(
+ std::is_nothrow_move_constructible::value) {
+ if (rhs.has_value()) {
+ this->construct(std::move(rhs.get()));
+ } else {
+ this->m_has_value = false;
+ }
+ }
+ optional_move_base &operator=(const optional_move_base &rhs) = default;
+ optional_move_base &operator=(optional_move_base &&rhs) = default;
+};
+
+// This class manages conditionally having a trivial copy assignment operator
+template
+struct optional_copy_assign_base : optional_move_base {
+ using optional_move_base::optional_move_base;
+};
+
+template
+struct optional_copy_assign_base : optional_move_base {
+ using optional_move_base::optional_move_base;
+
+ optional_copy_assign_base() = default;
+ optional_copy_assign_base(const optional_copy_assign_base &rhs) = default;
+
+ optional_copy_assign_base(optional_copy_assign_base &&rhs) = default;
+ optional_copy_assign_base &operator=(const optional_copy_assign_base &rhs) {
+ this->assign(rhs);
+ return *this;
+ }
+ optional_copy_assign_base &
+ operator=(optional_copy_assign_base &&rhs) = default;
+};
+
+// This class manages conditionally having a trivial move assignment operator
+// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
+// doesn't implement an analogue to std::is_trivially_move_assignable. We have
+// to make do with a non-trivial move assignment operator even if T is trivially
+// move assignable
+#ifndef TL_OPTIONAL_GCC49
+template ::value
+ &&std::is_trivially_move_constructible::value
+ &&std::is_trivially_move_assignable::value>
+struct optional_move_assign_base : optional_copy_assign_base {
+ using optional_copy_assign_base::optional_copy_assign_base;
+};
+#else
+template struct optional_move_assign_base;
+#endif
+
+template
+struct optional_move_assign_base : optional_copy_assign_base {
+ using optional_copy_assign_base::optional_copy_assign_base;
+
+ optional_move_assign_base() = default;
+ optional_move_assign_base(const optional_move_assign_base &rhs) = default;
+
+ optional_move_assign_base(optional_move_assign_base &&rhs) = default;
+
+ optional_move_assign_base &
+ operator=(const optional_move_assign_base &rhs) = default;
+
+ optional_move_assign_base &
+ operator=(optional_move_assign_base &&rhs) noexcept(
+ std::is_nothrow_move_constructible::value
+ &&std::is_nothrow_move_assignable::value) {
+ this->assign(std::move(rhs));
+ return *this;
+ }
+};
+
+// optional_delete_ctor_base will conditionally delete copy and move
+// constructors depending on whether T is copy/move constructible
+template ::value,
+ bool EnableMove = std::is_move_constructible::value>
+struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base &) = default;
+ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default;
+ optional_delete_ctor_base &
+ operator=(const optional_delete_ctor_base &) = default;
+ optional_delete_ctor_base &
+ operator=(optional_delete_ctor_base &&) noexcept = default;
+};
+
+template struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base &) = default;
+ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete;
+ optional_delete_ctor_base &
+ operator=(const optional_delete_ctor_base &) = default;
+ optional_delete_ctor_base &
+ operator=(optional_delete_ctor_base &&) noexcept = default;
+};
+
+template struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base &) = delete;
+ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default;
+ optional_delete_ctor_base &
+ operator=(const optional_delete_ctor_base &) = default;
+ optional_delete_ctor_base &
+ operator=(optional_delete_ctor_base &&) noexcept = default;
+};
+
+template struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base &) = delete;
+ optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete;
+ optional_delete_ctor_base &
+ operator=(const optional_delete_ctor_base &) = default;
+ optional_delete_ctor_base &
+ operator=(optional_delete_ctor_base &&) noexcept = default;
+};
+
+// optional_delete_assign_base will conditionally delete copy and move
+// constructors depending on whether T is copy/move constructible + assignable
+template ::value &&
+ std::is_copy_assignable::value),
+ bool EnableMove = (std::is_move_constructible::value &&
+ std::is_move_assignable::value)>
+struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base &) = default;
+ optional_delete_assign_base(optional_delete_assign_base &&) noexcept =
+ default;
+ optional_delete_assign_base &
+ operator=(const optional_delete_assign_base &) = default;
+ optional_delete_assign_base &
+ operator=(optional_delete_assign_base &&) noexcept = default;
+};
+
+template struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base &) = default;
+ optional_delete_assign_base(optional_delete_assign_base &&) noexcept =
+ default;
+ optional_delete_assign_base &
+ operator=(const optional_delete_assign_base &) = default;
+ optional_delete_assign_base &
+ operator=(optional_delete_assign_base &&) noexcept = delete;
+};
+
+template struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base &) = default;
+ optional_delete_assign_base(optional_delete_assign_base &&) noexcept =
+ default;
+ optional_delete_assign_base &
+ operator=(const optional_delete_assign_base &) = delete;
+ optional_delete_assign_base &
+ operator=(optional_delete_assign_base &&) noexcept = default;
+};
+
+template struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base &) = default;
+ optional_delete_assign_base(optional_delete_assign_base &&) noexcept =
+ default;
+ optional_delete_assign_base &
+ operator=(const optional_delete_assign_base &) = delete;
+ optional_delete_assign_base &
+ operator=(optional_delete_assign_base &&) noexcept = delete;
+};
+
+} // namespace detail
+
+/// A tag type to represent an empty optional
+struct nullopt_t {
+ struct do_not_use {};
+ constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {}
+};
+/// Represents an empty optional
+static constexpr nullopt_t nullopt{nullopt_t::do_not_use{},
+ nullopt_t::do_not_use{}};
+
+class bad_optional_access : public std::exception {
+public:
+ bad_optional_access() = default;
+ const char *what() const noexcept { return "Optional has no value"; }
+};
+
+/// An optional object is an object that contains the storage for another
+/// object and manages the lifetime of this contained object, if any. The
+/// contained object may be initialized after the optional object has been
+/// initialized, and may be destroyed before the optional object has been
+/// destroyed. The initialization state of the contained object is tracked by
+/// the optional object.
+template
+class optional : private detail::optional_move_assign_base,
+ private detail::optional_delete_ctor_base,
+ private detail::optional_delete_assign_base {
+ using base = detail::optional_move_assign_base;
+
+ static_assert(!std::is_same::value,
+ "instantiation of optional with in_place_t is ill-formed");
+ static_assert(!std::is_same, nullopt_t>::value,
+ "instantiation of optional with nullopt_t is ill-formed");
+
+public:
+// The different versions for C++14 and 11 are needed because deduced return
+// types are not SFINAE-safe. This provides better support for things like
+// generic lambdas. C.f.
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
+#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \
+ !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
+ /// Carries out some operation which returns an optional on the stored
+ /// object if there is one.
+ template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & {
+ using result = detail::invoke_result_t;
+ static_assert(detail::is_optional::value,
+ "F must return an optional");
+
+ return has_value() ? detail::invoke(std::forward(f), **this)
+ : result(nullopt);
+ }
+
+ template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && {
+ using result = detail::invoke_result_t;
+ static_assert(detail::is_optional