Update fmt to 10.0.0, lua to 5.4.6

This commit is contained in:
halx99 2023-05-16 15:47:55 +08:00
parent ef2cdd5bb1
commit 795522a078
83 changed files with 4293 additions and 6787 deletions

View File

@ -57,7 +57,7 @@
## {fmt}
- [![Upstream](https://img.shields.io/github/v/release/fmtlib/fmt?label=Upstream)](https://github.com/fmtlib/fmt)
- Version: 9.1.0
- Version: 10.0.0
- License: MIT
## FreeType
@ -108,7 +108,7 @@
## lua
- plainlua
- [![Upstream](https://img.shields.io/github/v/release/lua/lua?label=Upstream)](https://github.com/lua/lua) http://www.lua.org/
- Version: 5.4.4
- Version: 5.4.6
- License: MIT (http://www.lua.org/license.html)
- sol2

View File

@ -57,7 +57,7 @@
## {fmt}
- [![Upstream](https://img.shields.io/github/v/release/fmtlib/fmt?label=Upstream)](https://github.com/fmtlib/fmt)
- Version: 9.1.0
- Version: 10.0.0
- License: MIT
## FreeType
@ -108,7 +108,7 @@
## lua
- plainlua
- [![Upstream](https://img.shields.io/github/v/release/lua/lua?label=Upstream)](https://github.com/lua/lua) http://www.lua.org/
- Version: 5.4.4
- Version: 5.4.6
- License: MIT (http://www.lua.org/license.html)
- sol2

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1...3.18)
cmake_minimum_required(VERSION 3.8...3.26)
# Fallback for using newer policies on CMake <3.12.
if(${CMAKE_VERSION} VERSION_LESS 3.12)
@ -24,15 +24,86 @@ function(join result_var)
set(${result_var} "${result}" PARENT_SCOPE)
endfunction()
# DEPRECATED! Should be merged into add_module_library.
function(enable_module target)
if (MSVC)
set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc)
target_compile_options(${target}
PRIVATE /interface /ifcOutput ${BMI}
INTERFACE /reference fmt=${BMI})
set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI})
set_source_files_properties(${BMI} PROPERTIES GENERATED ON)
endif ()
set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI})
set_source_files_properties(${BMI} PROPERTIES GENERATED ON)
endfunction()
# Adds a library compiled with C++20 module support.
# `enabled` is a CMake variables that specifies if modules are enabled.
# If modules are disabled `add_module_library` falls back to creating a
# non-modular library.
#
# Usage:
# add_module_library(<name> [sources...] FALLBACK [sources...] [IF enabled])
function(add_module_library name)
cmake_parse_arguments(AML "" "IF" "FALLBACK" ${ARGN})
set(sources ${AML_UNPARSED_ARGUMENTS})
add_library(${name})
set_target_properties(${name} PROPERTIES LINKER_LANGUAGE CXX)
if (NOT ${${AML_IF}})
# Create a non-modular library.
target_sources(${name} PRIVATE ${AML_FALLBACK})
return()
endif ()
# Modules require C++20.
target_compile_features(${name} PUBLIC cxx_std_20)
if (CMAKE_COMPILER_IS_GNUCXX)
target_compile_options(${name} PUBLIC -fmodules-ts)
endif ()
# `std` is affected by CMake options and may be higher than C++20.
get_target_property(std ${name} CXX_STANDARD)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(pcms)
foreach (src ${sources})
get_filename_component(pcm ${src} NAME_WE)
set(pcm ${pcm}.pcm)
# Propagate -fmodule-file=*.pcm to targets that link with this library.
target_compile_options(
${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR}/${pcm})
# Use an absolute path to prevent target_link_libraries prepending -l
# to it.
set(pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR}/${pcm})
add_custom_command(
OUTPUT ${pcm}
COMMAND ${CMAKE_CXX_COMPILER}
-std=c++${std} -x c++-module --precompile -c
-o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR}/${src}
"-I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;-I>"
# Required by the -I generator expression above.
COMMAND_EXPAND_LISTS
DEPENDS ${src})
endforeach ()
# Add .pcm files as sources to make sure they are built before the library.
set(sources)
foreach (pcm ${pcms})
get_filename_component(pcm_we ${pcm} NAME_WE)
set(obj ${pcm_we}.o)
# Use an absolute path to prevent target_link_libraries prepending -l.
set(sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR}/${obj})
add_custom_command(
OUTPUT ${obj}
COMMAND ${CMAKE_CXX_COMPILER} $<TARGET_PROPERTY:${name},COMPILE_OPTIONS>
-c -o ${obj} ${pcm}
DEPENDS ${pcm})
endforeach ()
endif ()
target_sources(${name} PRIVATE ${sources})
endfunction()
include(CMakeParseArguments)
@ -75,7 +146,7 @@ option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
# Options that control generation of various targets.
option(FMT_DOC "Generate the doc target." ${FMT_MASTER_PROJECT})
option(FMT_INSTALL "Generate the install target." ${FMT_MASTER_PROJECT})
option(FMT_INSTALL "Generate the install target." ON)
option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT})
option(FMT_FUZZ "Generate the fuzz target." OFF)
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
@ -83,16 +154,6 @@ option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF)
set(FMT_CAN_MODULE OFF)
if (CMAKE_CXX_STANDARD GREATER 17 AND
# msvc 16.10-pre4
MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.29.30035)
set(FMT_CAN_MODULE OFF)
endif ()
if (NOT FMT_CAN_MODULE)
set(FMT_MODULE OFF)
message(STATUS "Module support is disabled.")
endif ()
if (FMT_TEST AND FMT_MODULE)
# The tests require {fmt} to be compiled as traditional library
message(STATUS "Testing is incompatible with build mode 'module'.")
@ -101,6 +162,10 @@ set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
if (FMT_SYSTEM_HEADERS)
set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
if(CMAKE_SYSTEM_NAME STREQUAL "MSDOS")
set(FMT_TEST OFF)
message(STATUS "MSDOS is incompatible with gtest")
endif()
# Get version from core.h
file(READ include/fmt/core.h core_h)
@ -118,23 +183,15 @@ message(STATUS "Version: ${FMT_VERSION}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
endif ()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
include(cxx14)
include(CheckCXXCompilerFlag)
include(JoinPaths)
list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_variadic_templates" index)
if (${index} GREATER -1)
# Use cxx_variadic_templates instead of more appropriate cxx_std_11 for
# compatibility with older CMake versions.
set(FMT_REQUIRED_FEATURES cxx_variadic_templates)
endif ()
message(STATUS "Required features: ${FMT_REQUIRED_FEATURES}")
if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
set_verbose(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING
"Preset for the export of private symbols")
@ -220,16 +277,18 @@ endfunction()
add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
format-inl.h os.h ostream.h printf.h ranges.h std.h
xchar.h)
if (FMT_MODULE)
set(FMT_SOURCES src/fmt.cc)
elseif (FMT_OS)
set(FMT_SOURCES src/format.cc src/os.cc)
else()
set(FMT_SOURCES src/format.cc)
set(FMT_SOURCES src/format.cc)
if (FMT_OS)
set(FMT_SOURCES ${FMT_SOURCES} src/os.cc)
endif ()
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
add_module_library(fmt src/fmt.cc FALLBACK
${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst
IF FMT_MODULE)
add_library(fmt::fmt ALIAS fmt)
if (FMT_MODULE)
enable_module(fmt)
endif ()
if (FMT_WERROR)
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
@ -237,11 +296,8 @@ endif ()
if (FMT_PEDANTIC)
target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
endif ()
if (FMT_MODULE)
enable_module(fmt)
endif ()
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
target_compile_features(fmt PUBLIC cxx_std_11)
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
@ -262,7 +318,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
endif ()
if (BUILD_SHARED_LIBS)
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
target_compile_definitions(fmt PRIVATE FMT_LIB_EXPORT INTERFACE FMT_SHARED)
endif ()
if (FMT_SAFE_DURATION_CAST)
target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST)
@ -272,7 +328,7 @@ add_library(fmt-header-only INTERFACE)
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
target_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES})
target_compile_features(fmt-header-only INTERFACE cxx_std_11)
target_include_directories(fmt-header-only ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
@ -339,8 +395,6 @@ if (FMT_INSTALL)
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
NAMESPACE fmt::)
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
endif ()

View File

@ -1,3 +1,434 @@
10.0.0 - 2023-05-09
-------------------
* Replaced Grisu with a new floating-point formatting algorithm for given
precision (`#3262 <https://github.com/fmtlib/fmt/issues/3262>`_,
`#2750 <https://github.com/fmtlib/fmt/issues/2750>`_,
`#3269 <https://github.com/fmtlib/fmt/pull/3269>`_,
`#3276 <https://github.com/fmtlib/fmt/pull/3276>`_).
The new algorithm is based on Dragonbox already used for the
shortest representation and gives substantial performance improvement:
.. image:: https://user-images.githubusercontent.com/33922675/
211956670-84891a09-6867-47d9-82fc-3230da7abe0f.png
* Red: new algorithm
* Green: new algorithm with ``FMT_USE_FULL_CACHE_DRAGONBOX`` defined to 1
* Blue: old algorithm
Thanks `@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_.
* Replaced ``snprintf``-based hex float formatter with an internal
implementation (`#3179 <https://github.com/fmtlib/fmt/pull/3179>`_,
`#3203 <https://github.com/fmtlib/fmt/pull/3203>`_).
This removes the last usage of ``s(n)printf`` in {fmt}.
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Fixed alignment of floating-point numbers with localization
(`#3263 <https://github.com/fmtlib/fmt/issues/3263>`_,
`#3272 <https://github.com/fmtlib/fmt/pull/3272>`_).
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Improved C++20 module support
(`#3134 <https://github.com/fmtlib/fmt/pull/3134>`_,
`#3254 <https://github.com/fmtlib/fmt/pull/3254>`_,
`#3386 <https://github.com/fmtlib/fmt/pull/3386>`_,
`#3387 <https://github.com/fmtlib/fmt/pull/3387>`_,
`#3388 <https://github.com/fmtlib/fmt/pull/3388>`_,
`#3392 <https://github.com/fmtlib/fmt/pull/3392>`_,
`#3397 <https://github.com/fmtlib/fmt/pull/3397>`_,
`#3399 <https://github.com/fmtlib/fmt/pull/3399>`_,
`#3400 <https://github.com/fmtlib/fmt/pull/3400>`_).
Thanks `@laitingsheng (Tinson Lai) <https://github.com/laitingsheng>`_,
`@Orvid (Orvid King) <https://github.com/Orvid>`_,
`@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
Switched to the `modules CMake library <https://github.com/vitaut/modules>`_
which allows building {fmt} as a C++20 module with clang::
CXX=clang++ cmake -DFMT_MODULE=ON .
make
* Made ``format_as`` work with any user-defined type and not just enums.
For example (`godbolt <https://godbolt.org/z/b7rqhq5Kh>`__):
.. code:: c++
#include <fmt/format.h>
struct floaty_mc_floatface {
double value;
};
auto format_as(floaty_mc_floatface f) { return f.value; }
int main() {
fmt::print("{:8}\n", floaty_mc_floatface{0.42}); // prints " 0.42"
}
* Removed deprecated implicit conversions for enums and conversions to primitive
types for compatibility with ``std::format`` and to prevent potential ODR
violations. Use ``format_as`` instead.
* Added support for fill, align and width to the time point formatter
(`#3237 <https://github.com/fmtlib/fmt/issues/3237>`_,
`#3260 <https://github.com/fmtlib/fmt/pull/3260>`_,
`#3275 <https://github.com/fmtlib/fmt/pull/3275>`_).
For example (`godbolt <https://godbolt.org/z/rKP6MGz6c>`__):
.. code:: c++
#include <fmt/chrono.h>
int main() {
// prints " 2023"
fmt::print("{:>8%Y}\n", std::chrono::system_clock::now());
}
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Implemented formatting of subseconds
(`#2207 <https://github.com/fmtlib/fmt/issues/2207>`_,
`#3117 <https://github.com/fmtlib/fmt/issues/3117>`_,
`#3115 <https://github.com/fmtlib/fmt/pull/3115>`_,
`#3143 <https://github.com/fmtlib/fmt/pull/3143>`_,
`#3144 <https://github.com/fmtlib/fmt/pull/3144>`_,
`#3349 <https://github.com/fmtlib/fmt/pull/3349>`_).
For example (`godbolt <https://godbolt.org/z/45738oGEo>`__):
.. code:: c++
#include <fmt/chrono.h>
int main() {
// prints 01.234567
fmt::print("{:%S}\n", std::chrono::microseconds(1234567));
}
Thanks `@patrickroocks (Patrick Roocks) <https://github.com/patrickroocks>`_
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
`@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
* Added precision support to ``%S``
(`#3148 <https://github.com/fmtlib/fmt/pull/3148>`_).
Thanks `@SappyJoy (Stepan Ponomaryov) <https://github.com/SappyJoy>`_
* Added support for ``std::utc_time``
(`#3098 <https://github.com/fmtlib/fmt/issues/3098>`_,
`#3110 <https://github.com/fmtlib/fmt/pull/3110>`_).
Thanks `@patrickroocks (Patrick Roocks) <https://github.com/patrickroocks>`_.
* Switched formatting of ``std::chrono::system_clock`` from local time to UTC
for compatibility with the standard
(`#3199 <https://github.com/fmtlib/fmt/issues/3199>`_,
`#3230 <https://github.com/fmtlib/fmt/pull/3230>`_).
Thanks `@ned14 (Niall Douglas) <https://github.com/ned14>`_.
* Added support for ``%Ez`` and ``%Oz`` to chrono formatters.
(`#3220 <https://github.com/fmtlib/fmt/issues/3220>`_,
`#3222 <https://github.com/fmtlib/fmt/pull/3222>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Improved validation of format specifiers for ``std::chrono::duration``
(`#3219 <https://github.com/fmtlib/fmt/issues/3219>`_,
`#3232 <https://github.com/fmtlib/fmt/pull/3232>`_).
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Fixed formatting of time points before the epoch
(`#3117 <https://github.com/fmtlib/fmt/issues/3117>`_,
`#3261 <https://github.com/fmtlib/fmt/pull/3261>`_).
For example (`godbolt <https://godbolt.org/z/f7bcznb3W>`__):
.. code:: c++
#include <fmt/chrono.h>
int main() {
auto t = std::chrono::system_clock::from_time_t(0) -
std::chrono::milliseconds(250);
fmt::print("{:%S}\n", t); // prints 59.750000000
}
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Experimental: implemented glibc extension for padding seconds, minutes and
hours (`#2959 <https://github.com/fmtlib/fmt/issues/2959>`_,
`#3271 <https://github.com/fmtlib/fmt/pull/3271>`_).
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Added a formatter for ``std::exception``
(`#2977 <https://github.com/fmtlib/fmt/issues/2977>`_,
`#3012 <https://github.com/fmtlib/fmt/issues/3012>`_,
`#3062 <https://github.com/fmtlib/fmt/pull/3062>`_,
`#3076 <https://github.com/fmtlib/fmt/pull/3076>`_,
`#3119 <https://github.com/fmtlib/fmt/pull/3119>`_).
For example (`godbolt <https://godbolt.org/z/8xoWGs9e4>`__):
.. code:: c++
#include <fmt/std.h>
#include <vector>
int main() {
try {
std::vector<bool>().at(0);
} catch(const std::exception& e) {
fmt::print("{}", e);
}
}
prints::
vector<bool>::_M_range_check: __n (which is 0) >= this->size() (which is 0)
on libstdc++.
Thanks `@zach2good (Zach Toogood) <https://github.com/zach2good>`_ and
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Moved ``std::error_code`` formatter from ``fmt/os.h`` to ``fmt/std.h``.
(`#3125 <https://github.com/fmtlib/fmt/pull/3125>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Added formatters for standard container adapters: ``std::priority_queue``,
``std::queue`` and ``std::stack``
(`#3215 <https://github.com/fmtlib/fmt/issues/3215>`_,
`#3279 <https://github.com/fmtlib/fmt/pull/3279>`_).
For example (`godbolt <https://godbolt.org/z/74h1xY9qK>`__):
.. code:: c++
#include <fmt/ranges.h>
#include <stack>
#include <vector>
int main() {
auto s = std::stack<bool, std::vector<bool>>();
for (auto b: {true, false, true}) s.push(b);
fmt::print("{}\n", s); // prints [true, false, true]
}
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Added a formatter for ``std::optional`` to ``fmt/std.h``.
Thanks `@tom-huntington <https://github.com/tom-huntington>`_.
* Fixed formatting of valueless by exception variants
(`#3347 <https://github.com/fmtlib/fmt/pull/3347>`_).
Thanks `@TheOmegaCarrot <https://github.com/TheOmegaCarrot>`_.
* Made ``fmt::ptr`` accept ``unique_ptr`` with a custom deleter
(`#3177 <https://github.com/fmtlib/fmt/pull/3177>`_).
Thanks `@hmbj (Hans-Martin B. Jensen) <https://github.com/hmbj>`_.
* Fixed formatting of noncopyable ranges and nested ranges of chars
(`#3158 <https://github.com/fmtlib/fmt/pull/3158>`_
`#3286 <https://github.com/fmtlib/fmt/issues/3286>`_,
`#3290 <https://github.com/fmtlib/fmt/pull/3290>`_).
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
* Fixed issues with formatting of paths and ranges of paths
(`#3319 <https://github.com/fmtlib/fmt/issues/3319>`_,
`#3321 <https://github.com/fmtlib/fmt/pull/3321>`_
`#3322 <https://github.com/fmtlib/fmt/issues/3322>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Improved handling of invalid Unicode in paths.
* Enabled compile-time checks on Apple clang 14 and later
(`#3331 <https://github.com/fmtlib/fmt/pull/3331>`_).
Thanks `@cloyce (Cloyce D. Spradling) <https://github.com/cloyce>`_.
* Improved compile-time checks of named arguments
(`#3105 <https://github.com/fmtlib/fmt/issues/3105>`_,
`#3214 <https://github.com/fmtlib/fmt/pull/3214>`_).
Thanks `@rbrich (Radek Brich) <https://github.com/rbrich>`_.
* Fixed formatting when both alignment and ``0`` are given
(`#3236 <https://github.com/fmtlib/fmt/issues/3236>`_,
`#3248 <https://github.com/fmtlib/fmt/pull/3248>`_).
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Improved Unicode support in the experimental file API on Windows
(`#3234 <https://github.com/fmtlib/fmt/issues/3234>`_,
`#3293 <https://github.com/fmtlib/fmt/pull/3293>`_).
Thanks `@Fros1er (Froster) <https://github.com/Fros1er>`_.
* Unified UTF transcoding
(`#3416 <https://github.com/fmtlib/fmt/pull/3416>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Added support for UTF-8 digit separators via an experimental locale facet
(`#1861 <https://github.com/fmtlib/fmt/issues/1861>`_).
For example (`godbolt <https://godbolt.org/z/f7bcznb3W>`__):
.. code:: c++
auto loc = std::locale(
std::locale(), new fmt::format_facet<std::locale>(""));
auto s = fmt::format(loc, "{:L}", 1000);
where ```` is U+2019 used as a digit separator in the de_CH locale.
* Added an overload of ``formatted_size`` that takes a locale
(`#3084 <https://github.com/fmtlib/fmt/issues/3084>`_,
`#3087 <https://github.com/fmtlib/fmt/pull/3087>`_).
Thanks `@gerboengels <https://github.com/gerboengels>`_.
* Removed the deprecated ``FMT_DEPRECATED_OSTREAM``.
* Fixed a UB when using a null ``std::string_view`` with ``fmt::to_string``
or format string compilation
(`#3241 <https://github.com/fmtlib/fmt/issues/3241>`_,
`#3244 <https://github.com/fmtlib/fmt/pull/3244>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Added ``starts_with`` to the fallback ``string_view`` implementation
(`#3080 <https://github.com/fmtlib/fmt/pull/3080>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Added ``fmt::basic_format_string::get()`` for compatibility with
``basic_format_string`` (`#3111 <https://github.com/fmtlib/fmt/pull/3111>`_).
Thanks `@huangqinjin <https://github.com/huangqinjin>`_.
* Added ``println`` for compatibility with C++23
(`#3267 <https://github.com/fmtlib/fmt/pull/3267>`_).
Thanks `@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_.
* Improved documentation
(`#3108 <https://github.com/fmtlib/fmt/issues/3108>`_,
`#3169 <https://github.com/fmtlib/fmt/issues/3169>`_,
`#3243 <https://github.com/fmtlib/fmt/pull/3243>`_).
`#3404 <https://github.com/fmtlib/fmt/pull/3404>`_).
Thanks `@Cleroth <https://github.com/Cleroth>`_ and
`@Vertexwahn <https://github.com/Vertexwahn>`_.
* Improved build configuration and tests
(`#3118 <https://github.com/fmtlib/fmt/pull/3118>`_,
`#3120 <https://github.com/fmtlib/fmt/pull/3120>`_,
`#3188 <https://github.com/fmtlib/fmt/pull/3188>`_,
`#3189 <https://github.com/fmtlib/fmt/issues/3189>`_,
`#3198 <https://github.com/fmtlib/fmt/pull/3198>`_,
`#3205 <https://github.com/fmtlib/fmt/pull/3205>`_,
`#3207 <https://github.com/fmtlib/fmt/pull/3207>`_,
`#3210 <https://github.com/fmtlib/fmt/pull/3210>`_,
`#3240 <https://github.com/fmtlib/fmt/pull/3240>`_,
`#3256 <https://github.com/fmtlib/fmt/pull/3256>`_,
`#3264 <https://github.com/fmtlib/fmt/pull/3264>`_,
`#3299 <https://github.com/fmtlib/fmt/issues/3299>`_,
`#3302 <https://github.com/fmtlib/fmt/pull/3302>`_,
`#3312 <https://github.com/fmtlib/fmt/pull/3312>`_,
`#3317 <https://github.com/fmtlib/fmt/issues/3317>`_,
`#3328 <https://github.com/fmtlib/fmt/pull/3328>`_,
`#3333 <https://github.com/fmtlib/fmt/pull/3333>`_,
`#3369 <https://github.com/fmtlib/fmt/pull/3369>`_,
`#3373 <https://github.com/fmtlib/fmt/issues/3373>`_,
`#3395 <https://github.com/fmtlib/fmt/pull/3395>`_,
`#3406 <https://github.com/fmtlib/fmt/pull/3406>`_,
`#3411 <https://github.com/fmtlib/fmt/pull/3411>`_).
Thanks `@dimztimz (Dimitrij Mijoski) <https://github.com/dimztimz>`_,
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
`@DavidKorczynski <https://github.com/DavidKorczynski>`_,
`@ChrisThrasher (Chris Thrasher) <https://github.com/ChrisThrasher>`_,
`@FrancoisCarouge (François Carouge) <https://github.com/FrancoisCarouge>`_,
`@kennyweiss (Kenny Weiss) <https://github.com/kennyweiss>`_,
`@luzpaz <https://github.com/luzpaz>`_,
`@codeinred (Alecto Irene Perez) <https://github.com/codeinred>`_,
`@Mixaill (Mikhail Paulyshka) <https://github.com/Mixaill>`_,
`@joycebrum (Joyce) <https://github.com/joycebrum>`_,
`@kevinhwang (Kevin Hwang) <https://github.com/kevinhwang>`_,
`@Vertexwahn <https://github.com/Vertexwahn>`_.
* Fixed a regression in handling empty format specifiers after a colon (``{:}``)
(`#3086 <https://github.com/fmtlib/fmt/pull/3086>`_).
Thanks `@oxidase (Michael Krasnyk) <https://github.com/oxidase>`_.
* Worked around a broken implementation of ``std::is_constant_evaluated`` in
some versions of libstdc++ on clang
(`#3247 <https://github.com/fmtlib/fmt/issues/3247>`_,
`#3281 <https://github.com/fmtlib/fmt/pull/3281>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Fixed formatting of volatile variables
(`#3068 <https://github.com/fmtlib/fmt/pull/3068>`_).
* Fixed various warnings and compilation issues
(`#3057 <https://github.com/fmtlib/fmt/pull/3057>`_,
`#3066 <https://github.com/fmtlib/fmt/pull/3066>`_,
`#3072 <https://github.com/fmtlib/fmt/pull/3072>`_,
`#3082 <https://github.com/fmtlib/fmt/pull/3082>`_,
`#3091 <https://github.com/fmtlib/fmt/pull/3091>`_,
`#3092 <https://github.com/fmtlib/fmt/issues/3092>`_,
`#3093 <https://github.com/fmtlib/fmt/pull/3093>`_,
`#3095 <https://github.com/fmtlib/fmt/pull/3095>`_,
`#3096 <https://github.com/fmtlib/fmt/issues/3096>`_,
`#3097 <https://github.com/fmtlib/fmt/pull/3097>`_,
`#3128 <https://github.com/fmtlib/fmt/issues/3128>`_,
`#3129 <https://github.com/fmtlib/fmt/pull/3129>`_,
`#3137 <https://github.com/fmtlib/fmt/pull/3137>`_,
`#3139 <https://github.com/fmtlib/fmt/pull/3139>`_,
`#3140 <https://github.com/fmtlib/fmt/issues/3140>`_,
`#3142 <https://github.com/fmtlib/fmt/pull/3142>`_,
`#3149 <https://github.com/fmtlib/fmt/issues/3149>`_,
`#3150 <https://github.com/fmtlib/fmt/pull/3150>`_,
`#3154 <https://github.com/fmtlib/fmt/issues/3154>`_,
`#3163 <https://github.com/fmtlib/fmt/issues/3163>`_,
`#3178 <https://github.com/fmtlib/fmt/issues/3178>`_,
`#3184 <https://github.com/fmtlib/fmt/pull/3184>`_,
`#3196 <https://github.com/fmtlib/fmt/pull/3196>`_,
`#3204 <https://github.com/fmtlib/fmt/issues/3204>`_,
`#3206 <https://github.com/fmtlib/fmt/pull/3206>`_,
`#3208 <https://github.com/fmtlib/fmt/pull/3208>`_,
`#3213 <https://github.com/fmtlib/fmt/issues/3213>`_,
`#3216 <https://github.com/fmtlib/fmt/pull/3216>`_,
`#3224 <https://github.com/fmtlib/fmt/issues/3224>`_,
`#3226 <https://github.com/fmtlib/fmt/issues/3226>`_,
`#3228 <https://github.com/fmtlib/fmt/issues/3228>`_,
`#3229 <https://github.com/fmtlib/fmt/pull/3229>`_,
`#3259 <https://github.com/fmtlib/fmt/pull/3259>`_,
`#3274 <https://github.com/fmtlib/fmt/issues/3274>`_,
`#3287 <https://github.com/fmtlib/fmt/issues/3287>`_,
`#3288 <https://github.com/fmtlib/fmt/pull/3288>`_,
`#3292 <https://github.com/fmtlib/fmt/issues/3292>`_,
`#3295 <https://github.com/fmtlib/fmt/pull/3295>`_,
`#3296 <https://github.com/fmtlib/fmt/pull/3296>`_,
`#3298 <https://github.com/fmtlib/fmt/issues/3298>`_,
`#3325 <https://github.com/fmtlib/fmt/issues/3325>`_,
`#3326 <https://github.com/fmtlib/fmt/pull/3326>`_,
`#3334 <https://github.com/fmtlib/fmt/issues/3334>`_,
`#3342 <https://github.com/fmtlib/fmt/issues/3342>`_,
`#3343 <https://github.com/fmtlib/fmt/pull/3343>`_,
`#3351 <https://github.com/fmtlib/fmt/issues/3351>`_,
`#3352 <https://github.com/fmtlib/fmt/pull/3352>`_,
`#3362 <https://github.com/fmtlib/fmt/pull/3362>`_,
`#3365 <https://github.com/fmtlib/fmt/issues/3365>`_,
`#3366 <https://github.com/fmtlib/fmt/pull/3366>`_,
`#3374 <https://github.com/fmtlib/fmt/pull/3374>`_,
`#3377 <https://github.com/fmtlib/fmt/issues/3377>`_,
`#3378 <https://github.com/fmtlib/fmt/pull/3378>`_,
`#3381 <https://github.com/fmtlib/fmt/issues/3381>`_,
`#3398 <https://github.com/fmtlib/fmt/pull/3398>`_,
`#3413 <https://github.com/fmtlib/fmt/pull/3413>`_,
`#3415 <https://github.com/fmtlib/fmt/issues/3415>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
`@gsjaardema (Greg Sjaardema) <https://github.com/gsjaardema>`_,
`@NewbieOrange <https://github.com/NewbieOrange>`_,
`@EngineLessCC (VivyaCC) <https://github.com/EngineLessCC>`_,
`@asmaloney (Andy Maloney) <https://github.com/asmaloney>`_,
`@HazardyKnusperkeks (Björn Schäpers)
<https://github.com/HazardyKnusperkeks>`_,
`@sergiud (Sergiu Deitsch) <https://github.com/sergiud>`_,
`@Youw (Ihor Dutchak) <https://github.com/Youw>`_,
`@thesmurph <https://github.com/thesmurph>`_,
`@czudziakm (Maksymilian Czudziak) <https://github.com/czudziakm>`_,
`@Roman-Koshelev <https://github.com/Roman-Koshelev>`_,
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
`@ShawnZhong (Shawn Zhong) <https://github.com/ShawnZhong>`_,
`@russelltg (Russell Greene) <https://github.com/russelltg>`_,
`@glebm (Gleb Mazovetskiy) <https://github.com/glebm>`_,
`@tmartin-gh <https://github.com/tmartin-gh>`_,
`@Zhaojun-Liu (June Liu) <https://github.com/Zhaojun-Liu>`_,
`@louiswins (Louis Wilson) <https://github.com/louiswins>`_,
`@mogemimi <https://github.com/mogemimi>`_.
9.1.0 - 2022-08-27
------------------
@ -105,6 +536,7 @@
`#2982 <https://github.com/fmtlib/fmt/pull/2982>`_,
`#2985 <https://github.com/fmtlib/fmt/pull/2985>`_,
`#2988 <https://github.com/fmtlib/fmt/issues/2988>`_,
`#2989 <https://github.com/fmtlib/fmt/issues/2989>`_,
`#3000 <https://github.com/fmtlib/fmt/issues/3000>`_,
`#3006 <https://github.com/fmtlib/fmt/issues/3006>`_,
`#3014 <https://github.com/fmtlib/fmt/issues/3014>`_,
@ -2260,7 +2692,7 @@
<https://github.com/kwesolowski>`_.
* Replaced ``FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION`` with the ``FMT_FUZZ``
macro to prevent interferring with fuzzing of projects using {fmt}
macro to prevent interfering with fuzzing of projects using {fmt}
(`#1650 <https://github.com/fmtlib/fmt/pull/1650>`_).
Thanks `@asraa (Asra Ali) <https://github.com/asraa>`_.

View File

@ -1,4 +1,4 @@
Copyright (c) 2012 - present, Victor Zverovich
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -47,7 +47,8 @@ Features
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
round-trip guarantees
round-trip guarantees using the `Dragonbox <https://github.com/jk-jeon/dragonbox>`_
algorithm
* Safe `printf implementation
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
extension for positional arguments
@ -191,24 +192,24 @@ Speed tests
================= ============= ===========
Library Method Run Time, s
================= ============= ===========
libc printf 1.04
libc++ std::ostream 3.05
{fmt} 6.1.1 fmt::print 0.75
Boost Format 1.67 boost::format 7.24
Folly Format folly::format 2.23
libc printf 0.91
libc++ std::ostream 2.49
{fmt} 9.1 fmt::print 0.74
Boost Format 1.80 boost::format 6.26
Folly Format folly::format 1.87
================= ============= ===========
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
{fmt} is the fastest of the benchmarked methods, ~20% faster than ``printf``.
The above results were generated by building ``tinyformat_test.cpp`` on macOS
10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
12.6.1 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
further details refer to the `source
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
IEEE754 ``float`` and ``double`` formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
`ryu <https://github.com/ulfjack/ryu>`_:
@ -322,8 +323,10 @@ Projects using this library
* `ccache <https://ccache.dev/>`_: a compiler cache
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: an analytical database
management system
* `Contour <https://github.com/contour-terminal/contour/>`_: a modern terminal emulator
* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
vehicle
@ -360,6 +363,10 @@ Projects using this library
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
* `libunicode <https://github.com/contour-terminal/libunicode/>`_: a modern C++17 Unicode library
* `MariaDB <https://mariadb.org/>`_: relational database management system
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
research programming language for concurrent ownership
@ -413,6 +420,9 @@ Projects using this library
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
MMORPG framework
* `🐙 userver framework <https://userver.tech/>`_: open-source asynchronous
framework with a rich set of abstractions and database drivers
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
terminal
@ -523,8 +533,7 @@ Maintainers
-----------
The {fmt} library is maintained by Victor Zverovich (`vitaut
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
<https://github.com/foonathan>`_) with contributions from many other people.
<https://github.com/vitaut>`_) with contributions from many other people.
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
Let us know if your contribution is not listed or mentioned incorrectly and

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
FMT_BEGIN_EXPORT
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
@ -423,26 +423,6 @@ FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
return ansi_color_escape<Char>(em);
}
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
int result = std::fputs(chars, stream);
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
int result = std::fputws(chars, stream);
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
template <typename Char> inline void reset_color(FILE* stream) {
fputs("\x1b[0m", stream);
}
template <> inline void reset_color<wchar_t>(FILE* stream) {
fputs(L"\x1b[0m", stream);
}
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
auto reset_color = string_view("\x1b[0m");
buffer.append(reset_color.begin(), reset_color.end());
@ -479,17 +459,19 @@ void vformat_to(buffer<Char>& buf, const text_style& ts,
FMT_END_DETAIL_NAMESPACE
template <typename S, typename Char = char_t<S>>
void vprint(std::FILE* f, const text_style& ts, const S& format,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
detail::vformat_to(buf, ts, detail::to_string_view(format), args);
inline void vprint(std::FILE* f, const text_style& ts, string_view fmt,
format_args args) {
// Legacy wide streams are not supported.
auto buf = memory_buffer();
detail::vformat_to(buf, ts, fmt, args);
if (detail::is_utf8()) {
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
} else {
buf.push_back(Char(0));
detail::fputs(buf.data(), f);
detail::print(f, string_view(buf.begin(), buf.size()));
return;
}
buf.push_back('\0');
int result = std::fputs(buf.data(), f);
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
/**
@ -566,7 +548,7 @@ OutputIt vformat_to(
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, ts, format_str, args);
return detail::get_iterator(buf);
return detail::get_iterator(buf, out);
}
/**
@ -645,7 +627,7 @@ FMT_CONSTEXPR auto styled(const T& value, text_style ts)
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
}
FMT_MODULE_EXPORT_END
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_

View File

@ -331,14 +331,14 @@ template <typename T, typename Char> struct parse_specs_result {
int next_arg_id;
};
constexpr int manual_indexing_id = -1;
enum { manual_indexing_id = -1 };
template <typename T, typename Char>
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
size_t pos, int next_arg_id) {
str.remove_prefix(pos);
auto ctx = compile_parse_context<Char>(str, max_value<int>(), nullptr, {},
next_arg_id);
auto ctx =
compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
@ -348,22 +348,18 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
template <typename Char> struct arg_id_handler {
arg_ref<Char> arg_id;
constexpr int operator()() {
constexpr int on_auto() {
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
return 0;
}
constexpr int operator()(int id) {
constexpr int on_index(int id) {
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr int operator()(basic_string_view<Char> id) {
constexpr int on_name(basic_string_view<Char> id) {
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr void on_error(const char* message) {
FMT_THROW(format_error(message));
}
};
template <typename Char> struct parse_arg_id_result {
@ -501,7 +497,7 @@ constexpr auto compile(S format_str) {
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
} // namespace detail
FMT_MODULE_EXPORT_BEGIN
FMT_BEGIN_EXPORT
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
@ -605,7 +601,7 @@ template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
} // namespace literals
#endif
FMT_MODULE_EXPORT_END
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_COMPILE_H_

File diff suppressed because it is too large Load Diff

View File

@ -9,13 +9,9 @@
#define FMT_FORMAT_INL_H_
#include <algorithm>
#include <cctype>
#include <cerrno> // errno
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstring> // std::memmove
#include <cwchar>
#include <exception>
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
@ -115,16 +111,43 @@ template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
return '.';
}
#endif
FMT_FUNC auto write_loc(appender out, loc_value value,
const format_specs<>& specs, locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
auto locale = loc.get<std::locale>();
// We cannot use the num_put<char> facet because it may produce output in
// a wrong encoding.
using facet = format_facet<std::locale>;
if (std::has_facet<facet>(locale))
return std::use_facet<facet>(locale).put(out, value, specs);
return facet(locale).put(out, value, specs);
#endif
return false;
}
} // namespace detail
#if !FMT_MSC_VERSION
FMT_API FMT_FUNC format_error::~format_error() noexcept = default;
template <typename Locale> typename Locale::id format_facet<Locale>::id;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template <typename Locale> format_facet<Locale>::format_facet(Locale& loc) {
auto& numpunct = std::use_facet<std::numpunct<char>>(loc);
grouping_ = numpunct.grouping();
if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep());
}
template <>
FMT_API FMT_FUNC auto format_facet<std::locale>::do_put(
appender out, loc_value val, const format_specs<>& specs) const -> bool {
return val.visit(
detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_});
}
#endif
FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str,
FMT_FUNC std::system_error vsystem_error(int error_code, string_view fmt,
format_args args) {
auto ec = std::error_code(error_code, std::generic_category());
return std::system_error(ec, vformat(format_str, args));
return std::system_error(ec, vformat(fmt, args));
}
namespace detail {
@ -143,58 +166,8 @@ FMT_CONSTEXPR inline uint64_t rotr(uint64_t n, uint32_t r) noexcept {
return (n >> r) | (n << (64 - r));
}
// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
inline uint128_fallback umul128(uint64_t x, uint64_t y) noexcept {
#if FMT_USE_INT128
auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)};
#elif defined(_MSC_VER) && defined(_M_X64)
auto result = uint128_fallback();
result.lo_ = _umul128(x, y, &result.hi_);
return result;
#else
const uint64_t mask = static_cast<uint64_t>(max_value<uint32_t>());
uint64_t a = x >> 32;
uint64_t b = x & mask;
uint64_t c = y >> 32;
uint64_t d = y & mask;
uint64_t ac = a * c;
uint64_t bc = b * c;
uint64_t ad = a * d;
uint64_t bd = b * d;
uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask);
return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
(intermediate << 32) + (bd & mask)};
#endif
}
// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox.
namespace dragonbox {
// Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
inline uint64_t umul128_upper64(uint64_t x, uint64_t y) noexcept {
#if FMT_USE_INT128
auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
return static_cast<uint64_t>(p >> 64);
#elif defined(_MSC_VER) && defined(_M_X64)
return __umulh(x, y);
#else
return umul128(x, y).high();
#endif
}
// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a
// 128-bit unsigned integer.
inline uint128_fallback umul192_upper128(uint64_t x,
uint128_fallback y) noexcept {
uint128_fallback r = umul128(x, y.high());
r += umul128_upper64(x, y.low());
return r;
}
// Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a
// 64-bit unsigned integer.
inline uint64_t umul96_upper64(uint32_t x, uint64_t y) noexcept {
@ -216,25 +189,13 @@ inline uint64_t umul96_lower64(uint32_t x, uint64_t y) noexcept {
return x * y;
}
// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from
// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1.
inline int floor_log10_pow2(int e) noexcept {
FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent");
static_assert((-1 >> 1) == -1, "right shift is not arithmetic");
return (e * 315653) >> 20;
}
// Various fast log computations.
inline int floor_log2_pow10(int e) noexcept {
FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent");
return (e * 1741647) >> 19;
}
inline int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept {
FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent");
return (e * 631305 - 261663) >> 21;
}
static constexpr struct {
FMT_INLINE_VARIABLE constexpr struct {
uint32_t divisor;
int shift_amount;
} div_small_pow10_infos[] = {{10, 16}, {100, 16}};
@ -288,7 +249,7 @@ inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) noexcept {
}
// Various subroutines using pow10 cache
template <class T> struct cache_accessor;
template <typename T> struct cache_accessor;
template <> struct cache_accessor<float> {
using carrier_uint = float_info<float>::carrier_uint;
@ -1009,8 +970,23 @@ template <> struct cache_accessor<double> {
{0xfcf62c1dee382c42, 0x46729e03dd9ed7b6},
{0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2},
{0xc5a05277621be293, 0xc7098b7305241886},
{ 0xf70867153aa2db38,
0xb8cbee4fc66d1ea8 }
{0xf70867153aa2db38, 0xb8cbee4fc66d1ea8},
{0x9a65406d44a5c903, 0x737f74f1dc043329},
{0xc0fe908895cf3b44, 0x505f522e53053ff3},
{0xf13e34aabb430a15, 0x647726b9e7c68ff0},
{0x96c6e0eab509e64d, 0x5eca783430dc19f6},
{0xbc789925624c5fe0, 0xb67d16413d132073},
{0xeb96bf6ebadf77d8, 0xe41c5bd18c57e890},
{0x933e37a534cbaae7, 0x8e91b962f7b6f15a},
{0xb80dc58e81fe95a1, 0x723627bbb5a4adb1},
{0xe61136f2227e3b09, 0xcec3b1aaa30dd91d},
{0x8fcac257558ee4e6, 0x213a4f0aa5e8a7b2},
{0xb3bd72ed2af29e1f, 0xa988e2cd4f62d19e},
{0xe0accfa875af45a7, 0x93eb1b80a33b8606},
{0x8c6c01c9498d8b88, 0xbc72f130660533c4},
{0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5},
{ 0xdb68c2ca82ed2a05,
0xa67398db9f6820e2 }
#else
{0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
{0xce5d73ff402d98e3, 0xfb0a3d212dc81290},
@ -1034,8 +1010,8 @@ template <> struct cache_accessor<double> {
{0x8da471a9de737e24, 0x5ceaecfed289e5d3},
{0xe4d5e82392a40515, 0x0fabaf3feaa5334b},
{0xb8da1662e7b00a17, 0x3d6a751f3b936244},
{ 0x95527a5202df0ccb,
0x0f37801e0c43ebc9 }
{0x95527a5202df0ccb, 0x0f37801e0c43ebc9},
{0xf13e34aabb430a15, 0x647726b9e7c68ff0}
#endif
};
@ -1138,8 +1114,12 @@ template <> struct cache_accessor<double> {
}
};
FMT_FUNC uint128_fallback get_cached_power(int k) noexcept {
return cache_accessor<double>::get_cached_power(k);
}
// Various integer checks
template <class T>
template <typename T>
bool is_left_endpoint_integer_shorter_interval(int exponent) noexcept {
const int case_shorter_interval_left_endpoint_lower_threshold = 2;
const int case_shorter_interval_left_endpoint_upper_threshold = 3;
@ -1150,8 +1130,12 @@ bool is_left_endpoint_integer_shorter_interval(int exponent) noexcept {
// Remove trailing zeros from n and return the number of zeros removed (float)
FMT_INLINE int remove_trailing_zeros(uint32_t& n) noexcept {
FMT_ASSERT(n != 0, "");
// Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1.
// See https://github.com/fmtlib/fmt/issues/3163 for more details.
const uint32_t mod_inv_5 = 0xcccccccd;
const uint32_t mod_inv_25 = mod_inv_5 * mod_inv_5;
// Casts are needed to workaround a bug in MSVC 19.22 and older.
const uint32_t mod_inv_25 =
static_cast<uint32_t>(uint64_t(mod_inv_5) * mod_inv_5);
int s = 0;
while (true) {
@ -1165,7 +1149,6 @@ FMT_INLINE int remove_trailing_zeros(uint32_t& n) noexcept {
n = q;
s |= 1;
}
return s;
}
@ -1223,7 +1206,7 @@ FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept {
}
// The main algorithm for shorter interval case
template <class T>
template <typename T>
FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) noexcept {
decimal_fp<T> ret_value;
// Compute k and beta
@ -1394,17 +1377,6 @@ small_divisor_case_label:
return ret_value;
}
} // namespace dragonbox
#ifdef _MSC_VER
FMT_FUNC auto fmt_snprintf(char* buf, size_t size, const char* fmt, ...)
-> int {
auto args = va_list();
va_start(args, fmt);
int result = vsnprintf_s(buf, size, _TRUNCATE, fmt, args);
va_end(args);
return result;
}
#endif
} // namespace detail
template <> struct formatter<detail::bigint> {
@ -1413,9 +1385,8 @@ template <> struct formatter<detail::bigint> {
return ctx.begin();
}
template <typename FormatContext>
auto format(const detail::bigint& n, FormatContext& ctx) const ->
typename FormatContext::iterator {
auto format(const detail::bigint& n, format_context& ctx) const
-> format_context::iterator {
auto out = ctx.out();
bool first = true;
for (auto i = n.bigits_.size(); i > 0; --i) {
@ -1474,57 +1445,44 @@ FMT_FUNC std::string vformat(string_view fmt, format_args args) {
}
namespace detail {
#ifdef _WIN32
#ifndef _WIN32
FMT_FUNC bool write_console(std::FILE*, string_view) { return false; }
#else
using dword = conditional_t<sizeof(long) == 4, unsigned long, unsigned>;
extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( //
void*, const void*, dword, dword*, void*);
FMT_FUNC bool write_console(std::FILE* f, string_view text) {
auto fd = _fileno(f);
if (_isatty(fd)) {
detail::utf8_to_utf16 u16(string_view(text.data(), text.size()));
auto written = detail::dword();
if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
u16.c_str(), static_cast<uint32_t>(u16.size()),
&written, nullptr)) {
return true;
}
}
// We return false if the file descriptor was not TTY, or it was but
// SetConsoleW failed which can happen if the output has been redirected to
// NUL. In both cases when we return false, we should attempt to do regular
// write via fwrite or std::ostream::write.
return false;
}
#endif
FMT_FUNC void print(std::FILE* f, string_view text) {
#ifdef _WIN32
if (write_console(f, text)) return;
#endif
detail::fwrite_fully(text.data(), 1, text.size(), f);
}
} // namespace detail
FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
memory_buffer buffer;
detail::vformat_to(buffer, format_str, args);
detail::print(f, {buffer.data(), buffer.size()});
if (!_isatty(fd)) return false;
auto u16 = utf8_to_utf16(text);
auto written = dword();
return WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)), u16.c_str(),
static_cast<uint32_t>(u16.size()), &written, nullptr);
}
#ifdef _WIN32
// Print assuming legacy (non-Unicode) encoding.
FMT_FUNC void detail::vprint_mojibake(std::FILE* f, string_view format_str,
format_args args) {
memory_buffer buffer;
detail::vformat_to(buffer, format_str,
FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args) {
auto buffer = memory_buffer();
detail::vformat_to(buffer, fmt,
basic_format_args<buffer_context<char>>(args));
fwrite_fully(buffer.data(), 1, buffer.size(), f);
}
#endif
FMT_FUNC void vprint(string_view format_str, format_args args) {
vprint(stdout, format_str, args);
FMT_FUNC void print(std::FILE* f, string_view text) {
if (!write_console(f, text)) fwrite_fully(text.data(), 1, text.size(), f);
}
} // namespace detail
FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) {
auto buffer = memory_buffer();
detail::vformat_to(buffer, fmt, args);
detail::print(f, {buffer.data(), buffer.size()});
}
FMT_FUNC void vprint(string_view fmt, format_args args) {
vprint(stdout, fmt, args);
}
namespace detail {

File diff suppressed because it is too large Load Diff

View File

@ -71,7 +71,7 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
FMT_BEGIN_EXPORT
/**
\rst
@ -120,48 +120,10 @@ template <typename Char> class basic_cstring_view {
using cstring_view = basic_cstring_view<char>;
using wcstring_view = basic_cstring_view<wchar_t>;
template <typename Char> struct formatter<std::error_code, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes(out, ec.category().name(),
basic_format_specs<Char>());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
}
};
#ifdef _WIN32
FMT_API const std::error_category& system_category() noexcept;
FMT_BEGIN_DETAIL_NAMESPACE
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
class utf16_to_utf8 {
private:
memory_buffer buffer_;
public:
utf16_to_utf8() {}
FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s);
operator string_view() const { return string_view(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const char* c_str() const { return &buffer_[0]; }
std::string str() const { return std::string(&buffer_[0], size()); }
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
// in case of memory allocation error.
FMT_API int convert(basic_string_view<wchar_t> s);
};
FMT_API void format_windows_error(buffer<char>& out, int error_code,
const char* message) noexcept;
FMT_END_DETAIL_NAMESPACE
@ -355,6 +317,12 @@ class FMT_API file {
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
buffered_file fdopen(const char* mode);
# if defined(_WIN32) && !defined(__MINGW32__)
// Opens a file and constructs a file object representing this file by
// wcstring_view filename. Windows only.
static file open_windows_file(wcstring_view path, int oflag);
# endif
};
// Returns the memory page size.
@ -397,6 +365,28 @@ struct ostream_params {
# endif
};
class file_buffer final : public buffer<char> {
file file_;
FMT_API void grow(size_t) override;
public:
FMT_API file_buffer(cstring_view path, const ostream_params& params);
FMT_API file_buffer(file_buffer&& other);
FMT_API ~file_buffer();
void flush() {
if (size() == 0) return;
file_.write(data(), size() * sizeof(data()[0]));
clear();
}
void close() {
flush();
file_.close();
}
};
FMT_END_DETAIL_NAMESPACE
// Added {} below to work around default constructor error known to
@ -404,49 +394,32 @@ FMT_END_DETAIL_NAMESPACE
constexpr detail::buffer_size buffer_size{};
/** A fast output stream which is not thread-safe. */
class FMT_API ostream final : private detail::buffer<char> {
class FMT_API ostream {
private:
file file_;
void grow(size_t) override;
FMT_MSC_WARNING(suppress : 4251)
detail::file_buffer buffer_;
ostream(cstring_view path, const detail::ostream_params& params)
: file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
}
: buffer_(path, params) {}
public:
ostream(ostream&& other)
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) {
other.clear();
other.set(nullptr, 0);
}
~ostream() {
flush();
delete[] data();
}
ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {}
void flush() {
if (size() == 0) return;
file_.write(data(), size());
clear();
}
~ostream();
void flush() { buffer_.flush(); }
template <typename... T>
friend ostream output_file(cstring_view path, T... params);
void close() {
flush();
file_.close();
}
void close() { buffer_.close(); }
/**
Formats ``args`` according to specifications in ``fmt`` and writes the
output to the file.
*/
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
vformat_to(detail::buffer_appender<char>(*this), fmt,
vformat_to(detail::buffer_appender<char>(buffer_), fmt,
fmt::make_format_args(args...));
}
};
@ -472,7 +445,7 @@ inline ostream output_file(cstring_view path, T... params) {
}
#endif // FMT_USE_FCNTL
FMT_MODULE_EXPORT_END
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_OS_H_

View File

@ -8,8 +8,8 @@
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include <fstream>
#include <ostream>
#include <fstream> // std::filebuf
#if defined(_WIN32) && defined(__GLIBCXX__)
# include <ext/stdio_filebuf.h>
# include <ext/stdio_sync_filebuf.h>
@ -21,48 +21,14 @@
FMT_BEGIN_NAMESPACE
template <typename OutputIt, typename Char> class basic_printf_context;
namespace detail {
// Checks if T has a user-defined operator<<.
template <typename T, typename Char, typename Enable = void>
class is_streamable {
private:
template <typename U>
static auto test(int)
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
<< std::declval<U>()) != 0>;
template <typename> static auto test(...) -> std::false_type;
using result = decltype(test<T>(0));
public:
is_streamable() = default;
static const bool value = result::value;
};
// Formatting of built-in types and arrays is intentionally disabled because
// it's handled by standard (non-ostream) formatters.
template <typename T, typename Char>
struct is_streamable<
T, Char,
enable_if_t<
std::is_arithmetic<T>::value || std::is_array<T>::value ||
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
std::is_same<T, std_string_view<Char>>::value ||
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
: std::false_type {};
// Generate a unique explicit instantion in every translation unit using a tag
// type in an anonymous namespace.
namespace {
struct file_access_tag {};
} // namespace
template <class Tag, class BufType, FILE* BufType::*FileMemberPtr>
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
class file_access {
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
};
@ -84,8 +50,8 @@ inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) {
#elif defined(_WIN32) && defined(__GLIBCXX__)
auto* rdbuf = os.rdbuf();
FILE* c_file;
if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
c_file = fbuf->file();
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
c_file = sfbuf->file();
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
c_file = fbuf->file();
else
@ -145,7 +111,7 @@ struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
-> OutputIt {
auto buffer = basic_memory_buffer<Char>();
format_value(buffer, value, ctx.locale());
detail::format_value(buffer, value, ctx.locale());
return formatter<basic_string_view<Char>, Char>::format(
{buffer.data(), buffer.size()}, ctx);
}
@ -180,13 +146,6 @@ auto streamed(const T& value) -> detail::streamed_view<T> {
namespace detail {
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
: basic_ostream_formatter<Char> {
using basic_ostream_formatter<Char>::format;
};
inline void vprint_directly(std::ostream& os, string_view format_str,
format_args args) {
auto buffer = memory_buffer();
@ -232,6 +191,19 @@ void print(std::wostream& os,
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
}
FMT_MODULE_EXPORT template <typename... T>
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
FMT_MODULE_EXPORT
template <typename... Args>
void println(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

View File

@ -14,7 +14,7 @@
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
FMT_BEGIN_EXPORT
template <typename T> struct printf_formatter { printf_formatter() = delete; };
@ -81,13 +81,13 @@ class printf_precision_handler {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
int operator()(T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big"));
throw_format_error("number is too big");
return (std::max)(static_cast<int>(value), 0);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
int operator()(T) {
FMT_THROW(format_error("precision is not integer"));
throw_format_error("precision is not integer");
return 0;
}
};
@ -194,12 +194,10 @@ template <typename Char> struct get_cstring {
// left alignment if it is negative.
template <typename Char> class printf_width_handler {
private:
using format_specs = basic_format_specs<Char>;
format_specs& specs_;
format_specs<Char>& specs_;
public:
explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
unsigned operator()(T value) {
@ -209,24 +207,31 @@ template <typename Char> class printf_width_handler {
width = 0 - width;
}
unsigned int_max = max_value<int>();
if (width > int_max) FMT_THROW(format_error("number is too big"));
if (width > int_max) throw_format_error("number is too big");
return static_cast<unsigned>(width);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
unsigned operator()(T) {
FMT_THROW(format_error("width is not integer"));
throw_format_error("width is not integer");
return 0;
}
};
// Workaround for a bug with the XL compiler when initializing
// printf_arg_formatter's base class.
template <typename Char>
auto make_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s)
-> arg_formatter<Char> {
return {iter, s, locale_ref()};
}
// The ``printf`` argument formatter.
template <typename OutputIt, typename Char>
class printf_arg_formatter : public arg_formatter<Char> {
private:
using base = arg_formatter<Char>;
using context_type = basic_printf_context<OutputIt, Char>;
using format_specs = basic_format_specs<Char>;
context_type& context_;
@ -237,8 +242,8 @@ class printf_arg_formatter : public arg_formatter<Char> {
}
public:
printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx)
: base{iter, s, locale_ref()}, context_(ctx) {}
printf_arg_formatter(OutputIt iter, format_specs<Char>& s, context_type& ctx)
: base(make_arg_formatter(iter, s)), context_(ctx) {}
OutputIt operator()(monostate value) { return base::operator()(value); }
@ -247,7 +252,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
// MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead.
if (std::is_same<T, Char>::value) {
format_specs fmt_specs = this->specs;
format_specs<Char> fmt_specs = this->specs;
if (fmt_specs.type != presentation_type::none &&
fmt_specs.type != presentation_type::chr) {
return (*this)(static_cast<int>(value));
@ -300,8 +305,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
};
template <typename Char>
void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
const Char* end) {
void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
@ -328,8 +332,8 @@ void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
}
template <typename Char, typename GetArg>
int parse_header(const Char*& it, const Char* end,
basic_format_specs<Char>& specs, GetArg get_arg) {
int parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
GetArg get_arg) {
int arg_index = -1;
Char c = *it;
if (c >= '0' && c <= '9') {
@ -344,7 +348,7 @@ int parse_header(const Char*& it, const Char* end,
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
if (value == -1) FMT_THROW(format_error("number is too big"));
if (value == -1) throw_format_error("number is too big");
specs.width = value;
return arg_index;
}
@ -355,7 +359,7 @@ int parse_header(const Char*& it, const Char* end,
if (it != end) {
if (*it >= '0' && *it <= '9') {
specs.width = parse_nonnegative_int(it, end, -1);
if (specs.width == -1) FMT_THROW(format_error("number is too big"));
if (specs.width == -1) throw_format_error("number is too big");
} else if (*it == '*') {
++it;
specs.width = static_cast<int>(visit_format_arg(
@ -365,12 +369,52 @@ int parse_header(const Char*& it, const Char* end,
return arg_index;
}
inline auto parse_printf_presentation_type(char c, type t)
-> presentation_type {
using pt = presentation_type;
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
switch (c) {
case 'd':
return in(t, integral_set) ? pt::dec : pt::none;
case 'o':
return in(t, integral_set) ? pt::oct : pt::none;
case 'x':
return in(t, integral_set) ? pt::hex_lower : pt::none;
case 'X':
return in(t, integral_set) ? pt::hex_upper : pt::none;
case 'a':
return in(t, float_set) ? pt::hexfloat_lower : pt::none;
case 'A':
return in(t, float_set) ? pt::hexfloat_upper : pt::none;
case 'e':
return in(t, float_set) ? pt::exp_lower : pt::none;
case 'E':
return in(t, float_set) ? pt::exp_upper : pt::none;
case 'f':
return in(t, float_set) ? pt::fixed_lower : pt::none;
case 'F':
return in(t, float_set) ? pt::fixed_upper : pt::none;
case 'g':
return in(t, float_set) ? pt::general_lower : pt::none;
case 'G':
return in(t, float_set) ? pt::general_upper : pt::none;
case 'c':
return in(t, integral_set) ? pt::chr : pt::none;
case 's':
return in(t, string_set | cstring_set) ? pt::string : pt::none;
case 'p':
return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
default:
return pt::none;
}
}
template <typename Char, typename Context>
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
using OutputIt = buffer_appender<Char>;
auto out = OutputIt(buf);
auto context = basic_printf_context<OutputIt, Char>(out, args);
using iterator = buffer_appender<Char>;
auto out = iterator(buf);
auto context = basic_printf_context<iterator, Char>(out, args);
auto parse_ctx = basic_printf_parse_context<Char>(format);
// Returns the argument with specified index or, if arg_index is -1, the next
@ -387,26 +431,25 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
const Char* end = parse_ctx.end();
auto it = start;
while (it != end) {
if (!detail::find<false, Char>(it, end, '%', it)) {
it = end; // detail::find leaves it == nullptr if it doesn't find '%'
if (!find<false, Char>(it, end, '%', it)) {
it = end; // find leaves it == nullptr if it doesn't find '%'.
break;
}
Char c = *it++;
if (it != end && *it == c) {
out = detail::write(
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
out = write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
start = ++it;
continue;
}
out = detail::write(out, basic_string_view<Char>(
start, detail::to_unsigned(it - 1 - start)));
out =
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
basic_format_specs<Char> specs;
auto specs = format_specs<Char>();
specs.align = align::right;
// Parse argument index, flags and width.
int arg_index = parse_header(it, end, specs, get_arg);
if (arg_index == 0) parse_ctx.on_error("argument not found");
if (arg_index == 0) throw_format_error("argument not found");
// Parse precision.
if (it != end && *it == '.') {
@ -417,7 +460,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
} else if (c == '*') {
++it;
specs.precision = static_cast<int>(
visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
visit_format_arg(printf_precision_handler(), get_arg(-1)));
} else {
specs.precision = 0;
}
@ -429,17 +472,15 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
if (specs.precision >= 0 && arg.is_integral())
specs.fill[0] =
' '; // Ignore '0' flag for non-numeric types or if '-' present.
if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) {
auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
auto str = visit_format_arg(get_cstring<Char>(), arg);
auto str_end = str + specs.precision;
auto nul = std::find(str, str_end, Char());
arg = detail::make_arg<basic_printf_context<OutputIt, Char>>(
arg = make_arg<basic_printf_context<iterator, Char>>(
basic_string_view<Char>(
str, detail::to_unsigned(nul != str_end ? nul - str
: specs.precision)));
str, to_unsigned(nul != str_end ? nul - str : specs.precision)));
}
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
specs.alt = false;
if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false;
if (specs.fill[0] == '0') {
if (arg.is_arithmetic() && specs.align != align::left)
specs.align = align::numeric;
@ -451,7 +492,6 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
// Parse length and convert the argument to the required type.
c = it != end ? *it++ : 0;
Char t = it != end ? *it : 0;
using detail::convert_arg;
switch (c) {
case 'h':
if (t == 'h') {
@ -490,7 +530,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
}
// Parse type.
if (it == end) FMT_THROW(format_error("invalid format string"));
if (it == end) throw_format_error("invalid format string");
char type = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
@ -501,22 +541,21 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
break;
case 'c':
visit_format_arg(
detail::char_converter<basic_printf_context<OutputIt, Char>>(arg),
arg);
char_converter<basic_printf_context<iterator, Char>>(arg), arg);
break;
}
}
specs.type = parse_presentation_type(type);
specs.type = parse_printf_presentation_type(type, arg.type());
if (specs.type == presentation_type::none)
parse_ctx.on_error("invalid type specifier");
throw_format_error("invalid format specifier");
start = it;
// Format argument.
out = visit_format_arg(
detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg);
printf_arg_formatter<iterator, Char>(out, specs, context), arg);
}
detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
}
FMT_END_DETAIL_NAMESPACE
@ -559,9 +598,9 @@ inline auto vsprintf(
const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
basic_memory_buffer<Char> buffer;
vprintf(buffer, detail::to_string_view(fmt), args);
return to_string(buffer);
auto buf = basic_memory_buffer<Char>();
detail::vprintf(buf, detail::to_string_view(fmt), args);
return to_string(buf);
}
/**
@ -586,10 +625,10 @@ inline auto vfprintf(
std::FILE* f, const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
basic_memory_buffer<Char> buffer;
vprintf(buffer, detail::to_string_view(fmt), args);
size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
auto buf = basic_memory_buffer<Char>();
detail::vprintf(buf, detail::to_string_view(fmt), args);
size_t size = buf.size();
return std::fwrite(buf.data(), sizeof(Char), size, f) < size
? -1
: static_cast<int>(size);
}
@ -634,7 +673,7 @@ inline auto printf(const S& fmt, const T&... args) -> int {
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
}
FMT_MODULE_EXPORT_END
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_

View File

@ -22,27 +22,25 @@ FMT_BEGIN_NAMESPACE
namespace detail {
template <typename RangeT, typename OutputIterator>
OutputIterator copy(const RangeT& range, OutputIterator out) {
template <typename Range, typename OutputIt>
auto copy(const Range& range, OutputIt out) -> OutputIt {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
return out;
}
template <typename OutputIterator>
OutputIterator copy(const char* str, OutputIterator out) {
template <typename OutputIt>
auto copy(const char* str, OutputIt out) -> OutputIt {
while (*str) *out++ = *str++;
return out;
}
template <typename OutputIterator>
OutputIterator copy(char ch, OutputIterator out) {
template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt {
*out++ = ch;
return out;
}
template <typename OutputIterator>
OutputIterator copy(wchar_t ch, OutputIterator out) {
template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
*out++ = ch;
return out;
}
@ -69,7 +67,7 @@ template <typename T> class is_map {
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_MAP_AS_LIST
#ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED!
static constexpr const bool value = false;
#else
static constexpr const bool value =
@ -82,7 +80,7 @@ template <typename T> class is_set {
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_SET_AS_LIST
#ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED!
static constexpr const bool value = false;
#else
static constexpr const bool value =
@ -157,8 +155,9 @@ template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(detail::range_begin(std::declval<T>())),
decltype(detail::range_end(std::declval<T>())),
enable_if_t<std::is_copy_constructible<T>::value>>>
: std::true_type {};
// the extra int here is because older versions of MSVC don't
// SFINAE properly unless there are distinct types
int>> : std::true_type {};
template <typename T>
struct is_range_<T, void>
@ -211,41 +210,61 @@ class is_tuple_formattable_ {
static constexpr const bool value = false;
};
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
template <std::size_t... I>
static std::true_type check2(index_sequence<I...>,
integer_sequence<bool, (I == I)...>);
template <std::size_t... Is>
static std::true_type check2(index_sequence<Is...>,
integer_sequence<bool, (Is == Is)...>);
static std::false_type check2(...);
template <std::size_t... I>
template <std::size_t... Is>
static decltype(check2(
index_sequence<I...>{},
index_sequence<Is...>{},
integer_sequence<
bool, (is_formattable<typename std::tuple_element<I, T>::type,
C>::value)...>{})) check(index_sequence<I...>);
bool, (is_formattable<typename std::tuple_element<Is, T>::type,
C>::value)...>{})) check(index_sequence<Is...>);
public:
static constexpr const bool value =
decltype(check(tuple_index_sequence<T>{}))::value;
};
template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
template <typename Tuple, typename F, size_t... Is>
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
using std::get;
// using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
(void)_; // blocks warnings
// Using a free function get<Is>(Tuple) now.
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
ignore_unused(unused);
}
template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
T const&) {
return {};
template <typename Tuple, typename F>
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
std::forward<Tuple>(t), std::forward<F>(f));
}
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
const auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
using std::get;
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
ignore_unused(unused);
}
template <typename Tuple1, typename Tuple2, typename F>
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
std::forward<F>(f));
}
namespace tuple {
// Workaround a bug in MSVC 2019 (v140).
template <typename Char, typename... T>
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
using std::get;
template <typename Tuple, typename Char, std::size_t... Is>
auto get_formatters(index_sequence<Is...>)
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
} // namespace tuple
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
// Older MSVC doesn't get the reference type correctly for arrays.
template <typename R> struct range_reference_type_impl {
@ -269,45 +288,37 @@ using range_reference_type =
template <typename Range>
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
template <typename Range>
using uncvref_first_type =
remove_cvref_t<decltype(std::declval<range_reference_type<Range>>().first)>;
template <typename Range>
using uncvref_second_type = remove_cvref_t<
decltype(std::declval<range_reference_type<Range>>().second)>;
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
*out++ = ',';
*out++ = ' ';
return out;
template <typename Formatter>
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
-> decltype(f.set_debug_format(set)) {
f.set_debug_format(set);
}
template <typename Formatter>
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
template <typename Char, typename OutputIt>
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
return write_escaped_string(out, str);
}
// These are not generic lambdas for compatibility with C++11.
template <typename ParseContext> struct parse_empty_specs {
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
f.parse(ctx);
detail::maybe_set_debug_format(f, true);
}
ParseContext& ctx;
};
template <typename FormatContext> struct format_tuple_element {
using char_type = typename FormatContext::char_type;
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
auto sv = std_string_view<Char>(str);
return write_range_entry<Char>(out, basic_string_view<Char>(sv));
}
template <typename T>
void operator()(const formatter<T, char_type>& f, const T& v) {
if (i > 0)
ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out()));
ctx.advance_to(f.format(v, ctx));
++i;
}
template <typename Char, typename OutputIt, typename Arg,
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
OutputIt write_range_entry(OutputIt out, const Arg v) {
return write_escaped_char(out, v);
}
template <
typename Char, typename OutputIt, typename Arg,
FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value &&
!std::is_same<Arg, Char>::value)>
OutputIt write_range_entry(OutputIt out, const Arg& v) {
return write<Char>(out, v);
}
int i;
FormatContext& ctx;
basic_string_view<char_type> separator;
};
} // namespace detail
@ -321,29 +332,20 @@ template <typename T, typename C> struct is_tuple_formattable {
detail::is_tuple_formattable_<T, C>::value;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char,
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
fmt::is_tuple_formattable<TupleT, Char>::value>> {
template <typename Tuple, typename Char>
struct formatter<Tuple, Char,
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
fmt::is_tuple_formattable<Tuple, Char>::value>> {
private:
decltype(detail::tuple::get_formatters<Tuple, Char>(
detail::tuple_index_sequence<Tuple>())) formatters_;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '('>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ')'>{};
// C++11 generic lambda for format().
template <typename FormatContext> struct format_each {
template <typename T> void operator()(const T& v) {
if (i > 0) out = detail::copy_str<Char>(separator, out);
out = detail::write_range_entry<Char>(out, v);
++i;
}
int i;
typename FormatContext::iterator& out;
basic_string_view<Char> separator;
};
public:
FMT_CONSTEXPR formatter() {}
@ -359,17 +361,21 @@ struct formatter<TupleT, Char,
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
auto it = ctx.begin();
if (it != ctx.end() && *it != '}')
FMT_THROW(format_error("invalid format specifier"));
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
return it;
}
template <typename FormatContext = format_context>
auto format(const TupleT& values, FormatContext& ctx) const
template <typename FormatContext>
auto format(const Tuple& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::copy_str<Char>(opening_bracket_, out);
detail::for_each(values, format_each<FormatContext>{0, out, separator_});
out = detail::copy_str<Char>(closing_bracket_, out);
return out;
ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out()));
detail::for_each2(
formatters_, value,
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
return detail::copy_str<Char>(closing_bracket_, ctx.out());
}
};
@ -398,12 +404,10 @@ template <typename Context> struct range_mapper {
};
template <typename Char, typename Element>
using range_formatter_type = conditional_t<
is_formattable<Element, Char>::value,
using range_formatter_type =
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
std::declval<Element>()))>,
Char>,
fallback_formatter<Element, Char>>;
Char>;
template <typename R>
using maybe_const_range =
@ -413,11 +417,8 @@ using maybe_const_range =
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
template <typename R, typename Char>
struct is_formattable_delayed
: disjunction<
is_formattable<uncvref_type<maybe_const_range<R>>, Char>,
has_fallback_formatter<uncvref_type<maybe_const_range<R>>, Char>> {};
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
#endif
} // namespace detail
template <typename T, typename Char, typename Enable = void>
@ -426,32 +427,16 @@ struct range_formatter;
template <typename T, typename Char>
struct range_formatter<
T, Char,
enable_if_t<conjunction<
std::is_same<T, remove_cvref_t<T>>,
disjunction<is_formattable<T, Char>,
detail::has_fallback_formatter<T, Char>>>::value>> {
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
is_formattable<T, Char>>::value>> {
private:
detail::range_formatter_type<Char, T> underlying_;
bool custom_specs_ = false;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '['>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ']'>{};
template <class U>
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, int)
-> decltype(u.set_debug_format()) {
u.set_debug_format();
}
template <class U>
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
FMT_CONSTEXPR void maybe_set_debug_format() {
maybe_set_debug_format(underlying_, 0);
}
public:
FMT_CONSTEXPR range_formatter() {}
@ -473,31 +458,24 @@ struct range_formatter<
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') {
maybe_set_debug_format();
return it;
}
if (*it == 'n') {
if (it != end && *it == 'n') {
set_brackets({}, {});
++it;
}
if (*it == '}') {
maybe_set_debug_format();
return it;
if (it != end && *it != '}') {
if (*it != ':') FMT_THROW(format_error("invalid format specifier"));
++it;
} else {
detail::maybe_set_debug_format(underlying_, true);
}
if (*it != ':')
FMT_THROW(format_error("no other top-level range formatters supported"));
custom_specs_ = true;
++it;
ctx.advance_to(it);
return underlying_.parse(ctx);
}
template <typename R, class FormatContext>
template <typename R, typename FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
detail::range_mapper<buffer_context<Char>> mapper;
auto out = ctx.out();
@ -507,7 +485,6 @@ struct range_formatter<
auto end = detail::range_end(range);
for (; it != end; ++it) {
if (i > 0) out = detail::copy_str<Char>(separator_, out);
;
ctx.advance_to(out);
out = underlying_.format(mapper.map(*it), ctx);
++i;
@ -520,13 +497,14 @@ struct range_formatter<
enum class range_format { disabled, map, set, sequence, string, debug_string };
namespace detail {
template <typename T> struct range_format_kind_ {
static constexpr auto value = std::is_same<range_reference_type<T>, T>::value
? range_format::disabled
: is_map<T>::value ? range_format::map
: is_set<T>::value ? range_format::set
: range_format::sequence;
};
template <typename T>
struct range_format_kind_
: std::integral_constant<range_format,
std::is_same<uncvref_type<T>, T>::value
? range_format::disabled
: is_map<T>::value ? range_format::map
: is_set<T>::value ? range_format::set
: range_format::sequence> {};
template <range_format K, typename R, typename Char, typename Enable = void>
struct range_default_formatter;
@ -601,9 +579,6 @@ template <typename Char, typename... T> struct tuple_join_view : detail::view {
: tuple(t), sep{s} {}
};
template <typename Char, typename... T>
using tuple_arg_join = tuple_join_view<Char, T...>;
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
// support in tuple_join. It is disabled by default because of issues with
// the dynamic width and precision.
@ -673,7 +648,42 @@ struct formatter<tuple_join_view<Char, T...>, Char> {
}
};
FMT_MODULE_EXPORT_BEGIN
namespace detail {
// Check if T has an interface like a container adaptor (e.g. std::stack,
// std::queue, std::priority_queue).
template <typename T> class is_container_adaptor_like {
template <typename U> static auto check(U* p) -> typename U::container_type;
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Container> struct all {
const Container& c;
auto begin() const -> typename Container::const_iterator { return c.begin(); }
auto end() const -> typename Container::const_iterator { return c.end(); }
};
} // namespace detail
template <typename T, typename Char>
struct formatter<T, Char,
enable_if_t<detail::is_container_adaptor_like<T>::value>>
: formatter<detail::all<typename T::container_type>, Char> {
using all = detail::all<typename T::container_type>;
template <typename FormatContext>
auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
struct getter : T {
static auto get(const T& t) -> all {
return {t.*(&getter::c)}; // Access c through the derived class.
}
};
return formatter<all>::format(getter::get(t), ctx);
}
};
FMT_BEGIN_EXPORT
/**
\rst
@ -716,7 +726,7 @@ auto join(std::initializer_list<T> list, string_view sep)
return join(std::begin(list), std::end(list), sep);
}
FMT_MODULE_EXPORT_END
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_

View File

@ -8,8 +8,12 @@
#ifndef FMT_STD_H_
#define FMT_STD_H_
#include <cstdlib>
#include <exception>
#include <memory>
#include <thread>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include "ostream.h"
@ -25,6 +29,19 @@
# if FMT_HAS_INCLUDE(<variant>)
# include <variant>
# endif
# if FMT_HAS_INCLUDE(<optional>)
# include <optional>
# endif
#endif
// GCC 4 does not support FMT_HAS_INCLUDE.
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
# include <cxxabi.h>
// Android NDK with gabi++ library on some architectures does not implement
// abi::__cxa_demangle().
# ifndef __GABIXX_CXXABI_H__
# define FMT_HAS_ABI_CXA_DEMANGLE
# endif
#endif
#ifdef __cpp_lib_filesystem
@ -39,12 +56,13 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
}
# ifdef _WIN32
template <>
inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted,
inline void write_escaped_path<char>(memory_buffer& quoted,
const std::filesystem::path& p) {
auto s = p.u8string();
write_escaped_string<char>(
std::back_inserter(quoted),
string_view(reinterpret_cast<const char*>(s.c_str()), s.size()));
auto buf = basic_memory_buffer<wchar_t>();
write_escaped_string<wchar_t>(std::back_inserter(buf), p.native());
// Convert UTF-16 to UTF-8.
if (!unicode_to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}))
FMT_THROW(std::runtime_error("invalid utf16"));
}
# endif
template <>
@ -57,13 +75,19 @@ inline void write_escaped_path<std::filesystem::path::value_type>(
} // namespace detail
FMT_MODULE_EXPORT
template <typename Char>
struct formatter<std::filesystem::path, Char>
: formatter<basic_string_view<Char>> {
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
auto out = formatter<basic_string_view<Char>>::parse(ctx);
this->set_debug_format(false);
return out;
}
template <typename FormatContext>
auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
typename FormatContext::iterator {
basic_memory_buffer<Char> quoted;
auto quoted = basic_memory_buffer<Char>();
detail::write_escaped_path(quoted, p);
return formatter<basic_string_view<Char>>::format(
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
@ -73,12 +97,58 @@ FMT_END_NAMESPACE
#endif
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename Char>
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
FMT_END_NAMESPACE
#ifdef __cpp_lib_optional
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename T, typename Char>
struct formatter<std::optional<T>, Char,
std::enable_if_t<is_formattable<T, Char>::value>> {
private:
formatter<T, Char> underlying_;
static constexpr basic_string_view<Char> optional =
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
'('>{};
static constexpr basic_string_view<Char> none =
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
template <class U>
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
-> decltype(u.set_debug_format(set)) {
u.set_debug_format(set);
}
template <class U>
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
public:
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
maybe_set_debug_format(underlying_, true);
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(std::optional<T> const& opt, FormatContext& ctx) const
-> decltype(ctx.out()) {
if (!opt) return detail::write<Char>(ctx.out(), none);
auto out = ctx.out();
out = detail::write<Char>(out, optional);
ctx.advance_to(out);
out = underlying_.format(*opt, ctx);
return detail::write(out, ')');
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_optional
#ifdef __cpp_lib_variant
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename Char> struct formatter<std::monostate, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
@ -100,19 +170,16 @@ template <typename T>
using variant_index_sequence =
std::make_index_sequence<std::variant_size<T>::value>;
// variant_size and variant_alternative check.
template <typename T, typename U = void>
struct is_variant_like_ : std::false_type {};
template <typename T>
struct is_variant_like_<T, std::void_t<decltype(std::variant_size<T>::value)>>
: std::true_type {};
template <typename> struct is_variant_like_ : std::false_type {};
template <typename... Types>
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
// formattable element check
// formattable element check.
template <typename T, typename C> class is_variant_formattable_ {
template <std::size_t... I>
template <std::size_t... Is>
static std::conjunction<
is_formattable<std::variant_alternative_t<I, T>, C>...>
check(std::index_sequence<I...>);
is_formattable<std::variant_alternative_t<Is, T>, C>...>
check(std::index_sequence<Is...>);
public:
static constexpr const bool value =
@ -130,7 +197,6 @@ auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
}
} // namespace detail
template <typename T> struct is_variant_like {
static constexpr const bool value = detail::is_variant_like_<T>::value;
};
@ -140,6 +206,7 @@ template <typename T, typename C> struct is_variant_formattable {
detail::is_variant_formattable_<T, C>::value;
};
FMT_MODULE_EXPORT
template <typename Variant, typename Char>
struct formatter<
Variant, Char,
@ -156,16 +223,127 @@ struct formatter<
auto out = ctx.out();
out = detail::write<Char>(out, "variant(");
std::visit(
[&](const auto& v) {
out = detail::write_variant_alternative<Char>(out, v);
},
value);
try {
std::visit(
[&](const auto& v) {
out = detail::write_variant_alternative<Char>(out, v);
},
value);
} catch (const std::bad_variant_access&) {
detail::write<Char>(out, "valueless by exception");
}
*out++ = ')';
return out;
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_variant
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename Char> struct formatter<std::error_code, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
}
};
FMT_MODULE_EXPORT
template <typename T, typename Char>
struct formatter<
T, Char,
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
private:
bool with_typename_ = false;
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (*it == 't') {
++it;
with_typename_ = true;
}
return it;
}
template <typename OutputIt>
auto format(const std::exception& ex,
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
format_specs<Char> spec;
auto out = ctx.out();
if (!with_typename_)
return detail::write_bytes(out, string_view(ex.what()), spec);
const std::type_info& ti = typeid(ex);
#ifdef FMT_HAS_ABI_CXA_DEMANGLE
int status = 0;
std::size_t size = 0;
std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr(
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
string_view demangled_name_view;
if (demangled_name_ptr) {
demangled_name_view = demangled_name_ptr.get();
// Normalization of stdlib inline namespace names.
// libc++ inline namespaces.
// std::__1::* -> std::*
// std::__1::__fs::* -> std::*
// libstdc++ inline namespaces.
// std::__cxx11::* -> std::*
// std::filesystem::__cxx11::* -> std::filesystem::*
if (demangled_name_view.starts_with("std::")) {
char* begin = demangled_name_ptr.get();
char* to = begin + 5; // std::
for (char *from = to, *end = begin + demangled_name_view.size();
from < end;) {
// This is safe, because demangled_name is NUL-terminated.
if (from[0] == '_' && from[1] == '_') {
char* next = from + 1;
while (next < end && *next != ':') next++;
if (next[0] == ':' && next[1] == ':') {
from = next + 2;
continue;
}
}
*to++ = *from++;
}
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
}
} else {
demangled_name_view = string_view(ti.name());
}
out = detail::write_bytes(out, demangled_name_view, spec);
#elif FMT_MSC_VERSION
string_view demangled_name_view(ti.name());
if (demangled_name_view.starts_with("class "))
demangled_name_view.remove_prefix(6);
else if (demangled_name_view.starts_with("struct "))
demangled_name_view.remove_prefix(7);
out = detail::write_bytes(out, demangled_name_view, spec);
#else
out = detail::write_bytes(out, string_view(ti.name()), spec);
#endif
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, Char(' '));
out = detail::write_bytes(out, string_view(ex.what()), spec);
return out;
}
};
FMT_END_NAMESPACE
#endif // FMT_STD_H_

View File

@ -12,13 +12,32 @@
#include "format.h"
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
# include <locale>
#endif
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T>
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
}
FMT_MODULE_EXPORT_BEGIN
inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out,
loc_value value, const format_specs<wchar_t>& specs,
locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
auto& numpunct =
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
auto separator = std::wstring();
auto grouping = numpunct.grouping();
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
#endif
return false;
}
} // namespace detail
FMT_BEGIN_EXPORT
using wstring_view = basic_string_view<wchar_t>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
@ -33,7 +52,9 @@ inline auto runtime(wstring_view s) -> wstring_view { return s; }
#else
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
inline auto runtime(wstring_view s) -> basic_runtime<wchar_t> { return {{s}}; }
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
return {{s}};
}
#endif
template <> struct is_char<wchar_t> : std::true_type {};
@ -126,7 +147,7 @@ auto vformat_to(OutputIt out, const S& format_str,
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, detail::to_string_view(format_str), args);
return detail::get_iterator(buf);
return detail::get_iterator(buf, out);
}
template <typename OutputIt, typename S, typename... Args,
@ -149,7 +170,7 @@ inline auto vformat_to(
auto&& buf = detail::get_buffer<Char>(out);
vformat_to(buf, detail::to_string_view(format_str), args,
detail::locale_ref(loc));
return detail::get_iterator(buf);
return detail::get_iterator(buf, out);
}
template <
@ -160,7 +181,7 @@ template <
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, loc, to_string_view(format_str),
return vformat_to(out, loc, detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));
}
@ -217,13 +238,22 @@ template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
}
template <typename... T>
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
/**
Converts *value* to ``std::wstring`` using the default format for type *T*.
*/
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
return format(FMT_STRING(L"{}"), value);
}
FMT_MODULE_EXPORT_END
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_XCHAR_H_

View File

@ -1,49 +1,44 @@
module;
#ifndef __cpp_modules
# error Module not supported.
#endif
// put all implementation-provided headers into the global module fragment
// to prevent attachment to this module
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
# define _CRT_SECURE_NO_WARNINGS
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && defined(_WIN32)
# define WIN32_LEAN_AND_MEAN
#endif
// Put all implementation-provided headers into the global module fragment
// to prevent attachment to this module.
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <chrono>
#include <climits>
#include <clocale>
#include <cmath>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cwchar>
#include <exception>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iterator>
#include <limits>
#include <locale>
#include <memory>
#include <optional>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <thread>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <variant>
#include <vector>
#include <version>
#if _MSC_VER
#if __has_include(<cxxabi.h>)
# include <cxxabi.h>
#endif
#if defined(_MSC_VER) || defined(__MINGW32__)
# include <intrin.h>
#endif
#if defined __APPLE__ || defined(__FreeBSD__)
@ -65,22 +60,38 @@ module;
# endif
#endif
#ifdef _WIN32
# if defined(__GLIBCXX__)
# include <ext/stdio_filebuf.h>
# include <ext/stdio_sync_filebuf.h>
# elif defined(_LIBCPP_VERSION)
# include <__std_stream>
# endif
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
export module fmt;
#define FMT_MODULE_EXPORT export
#define FMT_MODULE_EXPORT_BEGIN export {
#define FMT_MODULE_EXPORT_END }
#define FMT_BEGIN_EXPORT export {
#define FMT_END_EXPORT }
#define FMT_BEGIN_DETAIL_NAMESPACE \
} \
namespace detail {
#define FMT_END_DETAIL_NAMESPACE \
} \
export {
// all library-provided declarations and definitions
// must be in the module purview to be exported
// If you define FMT_ATTACH_TO_GLOBAL_MODULE
// - all declarations are detached from module 'fmt'
// - the module behaves like a traditional static library, too
// - all library symbols are mangled traditionally
// - you can mix TUs with either importing or #including the {fmt} API
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
extern "C++" {
#endif
// All library-provided declarations and definitions must be in the module
// purview to be exported.
#include "fmt/args.h"
#include "fmt/chrono.h"
#include "fmt/color.h"
@ -88,11 +99,17 @@ export module fmt;
#include "fmt/format.h"
#include "fmt/os.h"
#include "fmt/printf.h"
#include "fmt/std.h"
#include "fmt/xchar.h"
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
}
#endif
// gcc doesn't yet implement private module fragments
#if !FMT_GCC_VERSION
module : private;
module :private;
#endif
#include "format.cc"

View File

@ -28,12 +28,8 @@ template FMT_API auto decimal_point_impl(locale_ref) -> char;
template FMT_API void buffer<char>::append(const char*, const char*);
// DEPRECATED!
// There is no correspondent extern template in format.h because of
// incompatibility between clang and gcc (#2377).
template FMT_API void vformat_to(buffer<char>&, string_view,
basic_format_args<FMT_BUFFER_CONTEXT(char)>,
locale_ref);
typename vformat_args<>::type, locale_ref);
// Explicit instantiations for wchar_t.

View File

@ -72,34 +72,6 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; }
FMT_BEGIN_NAMESPACE
#ifdef _WIN32
detail::utf16_to_utf8::utf16_to_utf8(basic_string_view<wchar_t> s) {
if (int error_code = convert(s)) {
FMT_THROW(windows_error(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
int detail::utf16_to_utf8::convert(basic_string_view<wchar_t> s) {
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
// WideCharToMultiByte does not support zero length, handle separately.
buffer_.resize(1);
buffer_[0] = 0;
return 0;
}
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
nullptr, nullptr);
if (length == 0) return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
length, nullptr, nullptr);
if (length == 0) return GetLastError();
buffer_[length] = 0;
return 0;
}
namespace detail {
class system_message {
@ -140,8 +112,8 @@ class utf8_system_category final : public std::error_category {
std::string message(int error_code) const override {
system_message msg(error_code);
if (msg) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
unicode_to_utf8<wchar_t> utf8_message;
if (utf8_message.convert(msg)) {
return utf8_message.str();
}
}
@ -167,9 +139,10 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
FMT_TRY {
system_message msg(error_code);
if (msg) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
fmt::format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
unicode_to_utf8<wchar_t> utf8_message;
if (utf8_message.convert(msg)) {
fmt::format_to(buffer_appender<char>(out), FMT_STRING("{}: {}"),
message, string_view(utf8_message));
return;
}
}
@ -192,37 +165,47 @@ buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
nullptr);
if (!file_)
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"),
filename.c_str()));
}
void buffered_file::close() {
if (!file_) return;
int result = FMT_SYSTEM(fclose(file_));
file_ = nullptr;
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
if (result != 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
}
int buffered_file::descriptor() const {
#ifdef fileno // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL.
int fd = fileno(file_);
#else
int fd = FMT_POSIX_CALL(fileno(file_));
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
#endif
if (fd == -1)
FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor")));
return fd;
}
#if FMT_USE_FCNTL
file::file(cstring_view path, int oflag) {
# ifdef _WIN32
using mode_t = int;
using mode_t = int;
# endif
constexpr mode_t mode =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
constexpr mode_t default_open_mode =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
file::file(cstring_view path, int oflag) {
# if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
auto converted = detail::utf8_to_utf16(string_view(path.c_str()));
*this = file::open_windows_file(converted.c_str(), oflag);
# else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
# endif
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode)));
if (fd_ == -1)
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
FMT_THROW(
system_error(errno, FMT_STRING("cannot open file {}"), path.c_str()));
# endif
}
file::~file() noexcept {
@ -238,7 +221,8 @@ void file::close() {
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
if (result != 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
}
long long file::size() const {
@ -260,7 +244,7 @@ long long file::size() const {
using Stat = struct stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
FMT_THROW(system_error(errno, "cannot get file attributes"));
FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes")));
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
"return type of file::size is not large enough");
return file_stat.st_size;
@ -270,14 +254,16 @@ long long file::size() const {
std::size_t file::read(void* buffer, std::size_t count) {
rwresult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot read from file")));
return detail::to_unsigned(result);
}
std::size_t file::write(const void* buffer, std::size_t count) {
rwresult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
if (result < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
return detail::to_unsigned(result);
}
@ -286,7 +272,8 @@ file file::dup(int fd) {
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1)
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd));
FMT_THROW(system_error(
errno, FMT_STRING("cannot duplicate file descriptor {}"), fd));
return file(new_fd);
}
@ -294,8 +281,9 @@ void file::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
fd_, fd));
FMT_THROW(system_error(
errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_,
fd));
}
}
@ -320,7 +308,8 @@ void file::pipe(file& read_end, file& write_end) {
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds));
# endif
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
if (result != 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe")));
// The following assignments don't throw because read_fd and write_fd
// are closed.
read_end = file(fds[0]);
@ -334,28 +323,68 @@ buffered_file file::fdopen(const char* mode) {
# else
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
# endif
if (!f)
FMT_THROW(
system_error(errno, "cannot associate stream with file descriptor"));
if (!f) {
FMT_THROW(system_error(
errno, FMT_STRING("cannot associate stream with file descriptor")));
}
buffered_file bf(f);
fd_ = -1;
return bf;
}
# if defined(_WIN32) && !defined(__MINGW32__)
file file::open_windows_file(wcstring_view path, int oflag) {
int fd = -1;
auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode);
if (fd == -1) {
FMT_THROW(
system_error(err, FMT_STRING("cannot open file {}"),
detail::unicode_to_utf8<wchar_t>(path.c_str()).c_str()));
}
return file(fd);
}
# endif
# if !defined(__MSDOS__)
long getpagesize() {
# ifdef _WIN32
# ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
# else
# else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
if (size < 0)
FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size")));
return size;
# endif
# endif
}
# endif
FMT_API void ostream::grow(size_t) {
namespace detail {
void file_buffer::grow(size_t) {
if (this->size() == this->capacity()) flush();
}
file_buffer::file_buffer(cstring_view path,
const detail::ostream_params& params)
: file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
}
file_buffer::file_buffer(file_buffer&& other)
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) {
other.clear();
other.set(nullptr, 0);
}
file_buffer::~file_buffer() {
flush();
delete[] data();
}
} // namespace detail
ostream::~ostream() = default;
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE

View File

@ -1,15 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fmt_static
LOCAL_MODULE_FILENAME := libfmt
LOCAL_SRC_FILES := ../src/format.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CFLAGS += -std=c++11 -fexceptions
include $(BUILD_STATIC_LIBRARY)

View File

@ -1 +0,0 @@
<manifest package="net.fmtlib" />

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
This directory contains build support files such as
* CMake modules
* Build scripts

View File

@ -1,20 +0,0 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# A vagrant config for testing against gcc-4.8.
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.disksize.size = '15GB'
config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y g++ make wget git
wget -q https://github.com/Kitware/CMake/releases/download/v3.14.4/cmake-3.14.4-Linux-x86_64.tar.gz
tar xzf cmake-3.14.4-Linux-x86_64.tar.gz
ln -s `pwd`/cmake-3.14.4-Linux-x86_64/bin/cmake /usr/local/bin
SHELL
end

View File

@ -1 +0,0 @@
build --symlink_prefix=/ # Out of source build

View File

@ -1 +0,0 @@
5.1.1

View File

@ -1,28 +0,0 @@
cc_library(
name = "fmt",
srcs = [
#"src/fmt.cc", # No C++ module support
"src/format.cc",
"src/os.cc",
],
hdrs = [
"include/fmt/args.h",
"include/fmt/chrono.h",
"include/fmt/color.h",
"include/fmt/compile.h",
"include/fmt/core.h",
"include/fmt/format-inl.h",
"include/fmt/format.h",
"include/fmt/os.h",
"include/fmt/ostream.h",
"include/fmt/printf.h",
"include/fmt/ranges.h",
"include/fmt/std.h",
"include/fmt/xchar.h",
],
includes = [
"include",
],
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)

View File

@ -1,73 +0,0 @@
# Bazel support
To get [Bazel](https://bazel.build/) working with {fmt} you can copy the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` from this folder (`support/bazel`) to the root folder of this project. This way {fmt} gets bazelized and can be used with Bazel (e.g. doing a `bazel build //...` on {fmt}).
## Using {fmt} as a dependency
The following minimal example shows how to use {fmt} as a dependency within a Bazel project.
The following file structure is assumed:
```
example
├── BUILD.bazel
├── main.cpp
└── WORKSPACE.bazel
```
*main.cpp*:
```c++
#include "fmt/core.h"
int main() {
fmt::print("The answer is {}\n", 42);
}
```
The expected output of this example is `The answer is 42`.
*WORKSPACE.bazel*:
```python
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "fmt",
branch = "master",
remote = "https://github.com/fmtlib/fmt",
patch_cmds = [
"mv support/bazel/.bazelrc .bazelrc",
"mv support/bazel/.bazelversion .bazelversion",
"mv support/bazel/BUILD.bazel BUILD.bazel",
"mv support/bazel/WORKSPACE.bazel WORKSPACE.bazel",
],
# Windows-related patch commands are only needed in the case MSYS2 is not installed.
# More details about the installation process of MSYS2 on Windows systems can be found here:
# https://docs.bazel.build/versions/main/install-windows.html#installing-compilers-and-language-runtimes
# Even if MSYS2 is installed the Windows related patch commands can still be used.
patch_cmds_win = [
"Move-Item -Path support/bazel/.bazelrc -Destination .bazelrc",
"Move-Item -Path support/bazel/.bazelversion -Destination .bazelversion",
"Move-Item -Path support/bazel/BUILD.bazel -Destination BUILD.bazel",
"Move-Item -Path support/bazel/WORKSPACE.bazel -Destination WORKSPACE.bazel",
],
)
```
In the *WORKSPACE* file, the {fmt} GitHub repository is fetched. Using the attribute `patch_cmds` the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` are moved to the root of the {fmt} repository. This way the {fmt} repository is recognized as a bazelized workspace.
*BUILD.bazel*:
```python
cc_binary(
name = "Demo",
srcs = ["main.cpp"],
deps = ["@fmt"],
)
```
The *BUILD* file defines a binary named `Demo` that has a dependency to {fmt}.
To execute the binary you can run `bazel run //:Demo`.

View File

@ -1 +0,0 @@
workspace(name = "fmt")

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python
# Build the documentation in CI.
from __future__ import print_function
import errno, os, shutil, subprocess, sys, urllib
from subprocess import call, check_call, Popen, PIPE, STDOUT
def rmtree_if_exists(dir):
try:
shutil.rmtree(dir)
except OSError as e:
if e.errno == errno.ENOENT:
pass
# Build the docs.
fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.insert(0, os.path.join(fmt_dir, 'doc'))
import build
build.create_build_env()
html_dir = build.build_docs()
repo = 'fmtlib.github.io'
branch = os.environ['GITHUB_REF']
is_ci = 'CI' in os.environ
if is_ci and branch != 'refs/heads/master':
print('Branch: ' + branch)
exit(0) # Ignore non-master branches
if is_ci and 'KEY' not in os.environ:
# Don't update the repo if building in CI from an account that doesn't have
# push access.
print('Skipping update of ' + repo)
exit(0)
# Clone the fmtlib.github.io repo.
rmtree_if_exists(repo)
git_url = 'https://github.com/' if is_ci else 'git@github.com:'
check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)])
# Copy docs to the repo.
target_dir = os.path.join(repo, 'dev')
rmtree_if_exists(target_dir)
shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*'))
if is_ci:
check_call(['git', 'config', '--global', 'user.name', 'fmtbot'])
check_call(['git', 'config', '--global', 'user.email', 'viz@fmt.dev'])
# Push docs to GitHub pages.
check_call(['git', 'add', '--all'], cwd=repo)
if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo):
check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo)
cmd = 'git push'
if is_ci:
cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master'
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo)
# Print the output without the key.
print(p.communicate()[0].decode('utf-8').replace(os.environ['KEY'], '$KEY'))
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)

View File

@ -1,132 +0,0 @@
import java.nio.file.Paths
// General gradle arguments for root project
buildscript {
repositories {
google()
jcenter()
}
dependencies {
//
// https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
//
// Notice that 4.0.0 here is the version of [Android Gradle Plugin]
// Accroding to URL above you will need Gradle 6.1 or higher
//
classpath "com.android.tools.build:gradle:4.1.1"
}
}
repositories {
google()
jcenter()
}
// Project's root where CMakeLists.txt exists: rootDir/support/.cxx -> rootDir
def rootDir = Paths.get(project.buildDir.getParent()).getParent()
println("rootDir: ${rootDir}")
// Output: Shared library (.so) for Android
apply plugin: "com.android.library"
android {
compileSdkVersion 25 // Android 7.0
// Target ABI
// - This option controls target platform of module
// - The platform might be limited by compiler's support
// some can work with Clang(default), but some can work only with GCC...
// if bad, both toolchains might not support it
splits {
abi {
enable true
// Specify platforms for Application
reset()
include "arm64-v8a", "armeabi-v7a", "x86_64"
}
}
ndkVersion "21.3.6528147" // ANDROID_NDK_HOME is deprecated. Be explicit
defaultConfig {
minSdkVersion 21 // Android 5.0+
targetSdkVersion 25 // Follow Compile SDK
versionCode 34 // Follow release count
versionName "7.1.2" // Follow Official version
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared" // Specify Android STL
arguments "-DBUILD_SHARED_LIBS=true" // Build shared object
arguments "-DFMT_TEST=false" // Skip test
arguments "-DFMT_DOC=false" // Skip document
cppFlags "-std=c++17"
targets "fmt"
}
}
println(externalNativeBuild.cmake.cppFlags)
println(externalNativeBuild.cmake.arguments)
}
// External Native build
// - Use existing CMakeList.txt
// - Give path to CMake. This gradle file should be
// neighbor of the top level cmake
externalNativeBuild {
cmake {
version "3.10.0+"
path "${rootDir}/CMakeLists.txt"
// buildStagingDirectory "./build" // Custom path for cmake output
}
}
sourceSets{
// Android Manifest for Gradle
main {
manifest.srcFile "AndroidManifest.xml"
}
}
// https://developer.android.com/studio/build/native-dependencies#build_system_configuration
buildFeatures {
prefab true
prefabPublishing true
}
prefab {
fmt {
headers "${rootDir}/include"
}
}
}
assemble.doLast
{
// Instead of `ninja install`, Gradle will deploy the files.
// We are doing this since FMT is dependent to the ANDROID_STL after build
copy {
from "build/intermediates/cmake"
into "${rootDir}/libs"
}
// Copy debug binaries
copy {
from "${rootDir}/libs/debug/obj"
into "${rootDir}/libs/debug"
}
// Copy Release binaries
copy {
from "${rootDir}/libs/release/obj"
into "${rootDir}/libs/release"
}
// Remove empty directory
delete "${rootDir}/libs/debug/obj"
delete "${rootDir}/libs/release/obj"
// Copy AAR files. Notice that the aar is named after the folder of this script.
copy {
from "build/outputs/aar/support-release.aar"
into "${rootDir}/libs"
rename "support-release.aar", "fmt-release.aar"
}
copy {
from "build/outputs/aar/support-debug.aar"
into "${rootDir}/libs"
rename "support-debug.aar", "fmt-debug.aar"
}
}

View File

@ -1,54 +0,0 @@
# C++14 feature support detection
include(CheckCXXCompilerFlag)
function (fmt_check_cxx_compiler_flag flag result)
if (NOT MSVC)
check_cxx_compiler_flag("${flag}" ${result})
endif ()
endfunction ()
if (NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
endif()
message(STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
if (CMAKE_CXX_STANDARD EQUAL 20)
fmt_check_cxx_compiler_flag(-std=c++20 has_std_20_flag)
fmt_check_cxx_compiler_flag(-std=c++2a has_std_2a_flag)
if (has_std_20_flag)
set(CXX_STANDARD_FLAG -std=c++20)
elseif (has_std_2a_flag)
set(CXX_STANDARD_FLAG -std=c++2a)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 17)
fmt_check_cxx_compiler_flag(-std=c++17 has_std_17_flag)
fmt_check_cxx_compiler_flag(-std=c++1z has_std_1z_flag)
if (has_std_17_flag)
set(CXX_STANDARD_FLAG -std=c++17)
elseif (has_std_1z_flag)
set(CXX_STANDARD_FLAG -std=c++1z)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 14)
fmt_check_cxx_compiler_flag(-std=c++14 has_std_14_flag)
fmt_check_cxx_compiler_flag(-std=c++1y has_std_1y_flag)
if (has_std_14_flag)
set(CXX_STANDARD_FLAG -std=c++14)
elseif (has_std_1y_flag)
set(CXX_STANDARD_FLAG -std=c++1y)
endif ()
elseif (CMAKE_CXX_STANDARD EQUAL 11)
fmt_check_cxx_compiler_flag(-std=c++11 has_std_11_flag)
fmt_check_cxx_compiler_flag(-std=c++0x has_std_0x_flag)
if (has_std_11_flag)
set(CXX_STANDARD_FLAG -std=c++11)
elseif (has_std_0x_flag)
set(CXX_STANDARD_FLAG -std=c++0x)
endif ()
endif ()

View File

@ -1,53 +0,0 @@
#!/usr/bin/env python
# Compute 10 ** exp with exp in the range [min_exponent, max_exponent] and print
# normalized (with most-significant bit equal to 1) significands in hexadecimal.
from __future__ import print_function
min_exponent = -348
max_exponent = 340
step = 8
significand_size = 64
exp_offset = 2000
class fp:
pass
powers = []
for i, exp in enumerate(range(min_exponent, max_exponent + 1, step)):
result = fp()
n = 10 ** exp if exp >= 0 else 2 ** exp_offset / 10 ** -exp
k = significand_size + 1
# Convert to binary and round.
binary = '{:b}'.format(n)
result.f = (int('{:0<{}}'.format(binary[:k], k), 2) + 1) / 2
result.e = len(binary) - (exp_offset if exp < 0 else 0) - significand_size
powers.append(result)
# Sanity check.
exp_offset10 = 400
actual = result.f * 10 ** exp_offset10
if result.e > 0:
actual *= 2 ** result.e
else:
for j in range(-result.e):
actual /= 2
expected = 10 ** (exp_offset10 + exp)
precision = len('{}'.format(expected)) - len('{}'.format(actual - expected))
if precision < 19:
print('low precision:', precision)
exit(1)
print('Significands:', end='')
for i, fp in enumerate(powers):
if i % 3 == 0:
print(end='\n ')
print(' {:0<#16x}'.format(fp.f, ), end=',')
print('\n\nExponents:', end='')
for i, fp in enumerate(powers):
if i % 11 == 0:
print(end='\n ')
print(' {:5}'.format(fp.e), end=',')
print('\n\nMax exponent difference:',
max([x.e - powers[i - 1].e for i, x in enumerate(powers)][1:]))

View File

@ -1,581 +0,0 @@
"""Pythonic command-line interface parser that will make you smile.
* http://docopt.org
* Repository and issue-tracker: https://github.com/docopt/docopt
* Licensed under terms of MIT license (see LICENSE-MIT)
* Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com
"""
import sys
import re
__all__ = ['docopt']
__version__ = '0.6.1'
class DocoptLanguageError(Exception):
"""Error in construction of usage-message by developer."""
class DocoptExit(SystemExit):
"""Exit in case user invoked program with incorrect arguments."""
usage = ''
def __init__(self, message=''):
SystemExit.__init__(self, (message + '\n' + self.usage).strip())
class Pattern(object):
def __eq__(self, other):
return repr(self) == repr(other)
def __hash__(self):
return hash(repr(self))
def fix(self):
self.fix_identities()
self.fix_repeating_arguments()
return self
def fix_identities(self, uniq=None):
"""Make pattern-tree tips point to same object if they are equal."""
if not hasattr(self, 'children'):
return self
uniq = list(set(self.flat())) if uniq is None else uniq
for i, child in enumerate(self.children):
if not hasattr(child, 'children'):
assert child in uniq
self.children[i] = uniq[uniq.index(child)]
else:
child.fix_identities(uniq)
def fix_repeating_arguments(self):
"""Fix elements that should accumulate/increment values."""
either = [list(child.children) for child in transform(self).children]
for case in either:
for e in [child for child in case if case.count(child) > 1]:
if type(e) is Argument or type(e) is Option and e.argcount:
if e.value is None:
e.value = []
elif type(e.value) is not list:
e.value = e.value.split()
if type(e) is Command or type(e) is Option and e.argcount == 0:
e.value = 0
return self
def transform(pattern):
"""Expand pattern into an (almost) equivalent one, but with single Either.
Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
Quirks: [-a] => (-a), (-a...) => (-a -a)
"""
result = []
groups = [[pattern]]
while groups:
children = groups.pop(0)
parents = [Required, Optional, OptionsShortcut, Either, OneOrMore]
if any(t in map(type, children) for t in parents):
child = [c for c in children if type(c) in parents][0]
children.remove(child)
if type(child) is Either:
for c in child.children:
groups.append([c] + children)
elif type(child) is OneOrMore:
groups.append(child.children * 2 + children)
else:
groups.append(child.children + children)
else:
result.append(children)
return Either(*[Required(*e) for e in result])
class LeafPattern(Pattern):
"""Leaf/terminal node of a pattern tree."""
def __init__(self, name, value=None):
self.name, self.value = name, value
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
def flat(self, *types):
return [self] if not types or type(self) in types else []
def match(self, left, collected=None):
collected = [] if collected is None else collected
pos, match = self.single_match(left)
if match is None:
return False, left, collected
left_ = left[:pos] + left[pos + 1:]
same_name = [a for a in collected if a.name == self.name]
if type(self.value) in (int, list):
if type(self.value) is int:
increment = 1
else:
increment = ([match.value] if type(match.value) is str
else match.value)
if not same_name:
match.value = increment
return True, left_, collected + [match]
same_name[0].value += increment
return True, left_, collected
return True, left_, collected + [match]
class BranchPattern(Pattern):
"""Branch/inner node of a pattern tree."""
def __init__(self, *children):
self.children = list(children)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__,
', '.join(repr(a) for a in self.children))
def flat(self, *types):
if type(self) in types:
return [self]
return sum([child.flat(*types) for child in self.children], [])
class Argument(LeafPattern):
def single_match(self, left):
for n, pattern in enumerate(left):
if type(pattern) is Argument:
return n, Argument(self.name, pattern.value)
return None, None
@classmethod
def parse(class_, source):
name = re.findall('(<\S*?>)', source)[0]
value = re.findall('\[default: (.*)\]', source, flags=re.I)
return class_(name, value[0] if value else None)
class Command(Argument):
def __init__(self, name, value=False):
self.name, self.value = name, value
def single_match(self, left):
for n, pattern in enumerate(left):
if type(pattern) is Argument:
if pattern.value == self.name:
return n, Command(self.name, True)
else:
break
return None, None
class Option(LeafPattern):
def __init__(self, short=None, long=None, argcount=0, value=False):
assert argcount in (0, 1)
self.short, self.long, self.argcount = short, long, argcount
self.value = None if value is False and argcount else value
@classmethod
def parse(class_, option_description):
short, long, argcount, value = None, None, 0, False
options, _, description = option_description.strip().partition(' ')
options = options.replace(',', ' ').replace('=', ' ')
for s in options.split():
if s.startswith('--'):
long = s
elif s.startswith('-'):
short = s
else:
argcount = 1
if argcount:
matched = re.findall('\[default: (.*)\]', description, flags=re.I)
value = matched[0] if matched else None
return class_(short, long, argcount, value)
def single_match(self, left):
for n, pattern in enumerate(left):
if self.name == pattern.name:
return n, pattern
return None, None
@property
def name(self):
return self.long or self.short
def __repr__(self):
return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
self.argcount, self.value)
class Required(BranchPattern):
def match(self, left, collected=None):
collected = [] if collected is None else collected
l = left
c = collected
for pattern in self.children:
matched, l, c = pattern.match(l, c)
if not matched:
return False, left, collected
return True, l, c
class Optional(BranchPattern):
def match(self, left, collected=None):
collected = [] if collected is None else collected
for pattern in self.children:
m, left, collected = pattern.match(left, collected)
return True, left, collected
class OptionsShortcut(Optional):
"""Marker/placeholder for [options] shortcut."""
class OneOrMore(BranchPattern):
def match(self, left, collected=None):
assert len(self.children) == 1
collected = [] if collected is None else collected
l = left
c = collected
l_ = None
matched = True
times = 0
while matched:
# could it be that something didn't match but changed l or c?
matched, l, c = self.children[0].match(l, c)
times += 1 if matched else 0
if l_ == l:
break
l_ = l
if times >= 1:
return True, l, c
return False, left, collected
class Either(BranchPattern):
def match(self, left, collected=None):
collected = [] if collected is None else collected
outcomes = []
for pattern in self.children:
matched, _, _ = outcome = pattern.match(left, collected)
if matched:
outcomes.append(outcome)
if outcomes:
return min(outcomes, key=lambda outcome: len(outcome[1]))
return False, left, collected
class Tokens(list):
def __init__(self, source, error=DocoptExit):
self += source.split() if hasattr(source, 'split') else source
self.error = error
@staticmethod
def from_pattern(source):
source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source)
source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s]
return Tokens(source, error=DocoptLanguageError)
def move(self):
return self.pop(0) if len(self) else None
def current(self):
return self[0] if len(self) else None
def parse_long(tokens, options):
"""long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
long, eq, value = tokens.move().partition('=')
assert long.startswith('--')
value = None if eq == value == '' else value
similar = [o for o in options if o.long == long]
if tokens.error is DocoptExit and similar == []: # if no exact match
similar = [o for o in options if o.long and o.long.startswith(long)]
if len(similar) > 1: # might be simply specified ambiguously 2+ times?
raise tokens.error('%s is not a unique prefix: %s?' %
(long, ', '.join(o.long for o in similar)))
elif len(similar) < 1:
argcount = 1 if eq == '=' else 0
o = Option(None, long, argcount)
options.append(o)
if tokens.error is DocoptExit:
o = Option(None, long, argcount, value if argcount else True)
else:
o = Option(similar[0].short, similar[0].long,
similar[0].argcount, similar[0].value)
if o.argcount == 0:
if value is not None:
raise tokens.error('%s must not have an argument' % o.long)
else:
if value is None:
if tokens.current() in [None, '--']:
raise tokens.error('%s requires argument' % o.long)
value = tokens.move()
if tokens.error is DocoptExit:
o.value = value if value is not None else True
return [o]
def parse_shorts(tokens, options):
"""shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
token = tokens.move()
assert token.startswith('-') and not token.startswith('--')
left = token.lstrip('-')
parsed = []
while left != '':
short, left = '-' + left[0], left[1:]
similar = [o for o in options if o.short == short]
if len(similar) > 1:
raise tokens.error('%s is specified ambiguously %d times' %
(short, len(similar)))
elif len(similar) < 1:
o = Option(short, None, 0)
options.append(o)
if tokens.error is DocoptExit:
o = Option(short, None, 0, True)
else: # why copying is necessary here?
o = Option(short, similar[0].long,
similar[0].argcount, similar[0].value)
value = None
if o.argcount != 0:
if left == '':
if tokens.current() in [None, '--']:
raise tokens.error('%s requires argument' % short)
value = tokens.move()
else:
value = left
left = ''
if tokens.error is DocoptExit:
o.value = value if value is not None else True
parsed.append(o)
return parsed
def parse_pattern(source, options):
tokens = Tokens.from_pattern(source)
result = parse_expr(tokens, options)
if tokens.current() is not None:
raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
return Required(*result)
def parse_expr(tokens, options):
"""expr ::= seq ( '|' seq )* ;"""
seq = parse_seq(tokens, options)
if tokens.current() != '|':
return seq
result = [Required(*seq)] if len(seq) > 1 else seq
while tokens.current() == '|':
tokens.move()
seq = parse_seq(tokens, options)
result += [Required(*seq)] if len(seq) > 1 else seq
return [Either(*result)] if len(result) > 1 else result
def parse_seq(tokens, options):
"""seq ::= ( atom [ '...' ] )* ;"""
result = []
while tokens.current() not in [None, ']', ')', '|']:
atom = parse_atom(tokens, options)
if tokens.current() == '...':
atom = [OneOrMore(*atom)]
tokens.move()
result += atom
return result
def parse_atom(tokens, options):
"""atom ::= '(' expr ')' | '[' expr ']' | 'options'
| long | shorts | argument | command ;
"""
token = tokens.current()
result = []
if token in '([':
tokens.move()
matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
result = pattern(*parse_expr(tokens, options))
if tokens.move() != matching:
raise tokens.error("unmatched '%s'" % token)
return [result]
elif token == 'options':
tokens.move()
return [OptionsShortcut()]
elif token.startswith('--') and token != '--':
return parse_long(tokens, options)
elif token.startswith('-') and token not in ('-', '--'):
return parse_shorts(tokens, options)
elif token.startswith('<') and token.endswith('>') or token.isupper():
return [Argument(tokens.move())]
else:
return [Command(tokens.move())]
def parse_argv(tokens, options, options_first=False):
"""Parse command-line argument vector.
If options_first:
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
else:
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
"""
parsed = []
while tokens.current() is not None:
if tokens.current() == '--':
return parsed + [Argument(None, v) for v in tokens]
elif tokens.current().startswith('--'):
parsed += parse_long(tokens, options)
elif tokens.current().startswith('-') and tokens.current() != '-':
parsed += parse_shorts(tokens, options)
elif options_first:
return parsed + [Argument(None, v) for v in tokens]
else:
parsed.append(Argument(None, tokens.move()))
return parsed
def parse_defaults(doc):
defaults = []
for s in parse_section('options:', doc):
# FIXME corner case "bla: options: --foo"
_, _, s = s.partition(':') # get rid of "options:"
split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:]
split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
options = [Option.parse(s) for s in split if s.startswith('-')]
defaults += options
return defaults
def parse_section(name, source):
pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
re.IGNORECASE | re.MULTILINE)
return [s.strip() for s in pattern.findall(source)]
def formal_usage(section):
_, _, section = section.partition(':') # drop "usage:"
pu = section.split()
return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
def extras(help, version, options, doc):
if help and any((o.name in ('-h', '--help')) and o.value for o in options):
print(doc.strip("\n"))
sys.exit()
if version and any(o.name == '--version' and o.value for o in options):
print(version)
sys.exit()
class Dict(dict):
def __repr__(self):
return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
def docopt(doc, argv=None, help=True, version=None, options_first=False):
"""Parse `argv` based on command-line interface described in `doc`.
`docopt` creates your command-line interface based on its
description that you pass as `doc`. Such description can contain
--options, <positional-argument>, commands, which could be
[optional], (required), (mutually | exclusive) or repeated...
Parameters
----------
doc : str
Description of your command-line interface.
argv : list of str, optional
Argument vector to be parsed. sys.argv[1:] is used if not
provided.
help : bool (default: True)
Set to False to disable automatic help on -h or --help
options.
version : any object
If passed, the object will be printed if --version is in
`argv`.
options_first : bool (default: False)
Set to True to require options precede positional arguments,
i.e. to forbid options and positional arguments intermix.
Returns
-------
args : dict
A dictionary, where keys are names of command-line elements
such as e.g. "--verbose" and "<path>", and values are the
parsed values of those elements.
Example
-------
>>> from docopt import docopt
>>> doc = '''
... Usage:
... my_program tcp <host> <port> [--timeout=<seconds>]
... my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
... my_program (-h | --help | --version)
...
... Options:
... -h, --help Show this screen and exit.
... --baud=<n> Baudrate [default: 9600]
... '''
>>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
>>> docopt(doc, argv)
{'--baud': '9600',
'--help': False,
'--timeout': '30',
'--version': False,
'<host>': '127.0.0.1',
'<port>': '80',
'serial': False,
'tcp': True}
See also
--------
* For video introduction see http://docopt.org
* Full documentation is available in README.rst as well as online
at https://github.com/docopt/docopt#readme
"""
argv = sys.argv[1:] if argv is None else argv
usage_sections = parse_section('usage:', doc)
if len(usage_sections) == 0:
raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
if len(usage_sections) > 1:
raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
DocoptExit.usage = usage_sections[0]
options = parse_defaults(doc)
pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
# [default] syntax for argument is disabled
#for a in pattern.flat(Argument):
# same_name = [d for d in arguments if d.name == a.name]
# if same_name:
# a.value = same_name[0].value
argv = parse_argv(Tokens(argv), list(options), options_first)
pattern_options = set(pattern.flat(Option))
for options_shortcut in pattern.flat(OptionsShortcut):
doc_options = parse_defaults(doc)
options_shortcut.children = list(set(doc_options) - pattern_options)
#if any_options:
# options_shortcut.children += [Option(o.short, o.long, o.argcount)
# for o in argv if type(o) is Option]
extras(help, version, argv, doc)
matched, left, collected = pattern.fix().match(argv)
if matched and left == []: # better error message if left?
return Dict((a.name, a.value) for a in (pattern.flat() + collected))
raise DocoptExit()

View File

@ -1,303 +0,0 @@
#!/usr/bin/env python3
"""Manage site and releases.
Usage:
manage.py release [<branch>]
manage.py site
For the release command $FMT_TOKEN should contain a GitHub personal access token
obtained from https://github.com/settings/tokens.
"""
from __future__ import print_function
import datetime, docopt, errno, fileinput, json, os
import re, requests, shutil, sys, tempfile
from contextlib import contextmanager
from distutils.version import LooseVersion
from subprocess import check_call
class Git:
def __init__(self, dir):
self.dir = dir
def call(self, method, args, **kwargs):
return check_call(['git', method] + list(args), **kwargs)
def add(self, *args):
return self.call('add', args, cwd=self.dir)
def checkout(self, *args):
return self.call('checkout', args, cwd=self.dir)
def clean(self, *args):
return self.call('clean', args, cwd=self.dir)
def clone(self, *args):
return self.call('clone', list(args) + [self.dir])
def commit(self, *args):
return self.call('commit', args, cwd=self.dir)
def pull(self, *args):
return self.call('pull', args, cwd=self.dir)
def push(self, *args):
return self.call('push', args, cwd=self.dir)
def reset(self, *args):
return self.call('reset', args, cwd=self.dir)
def update(self, *args):
clone = not os.path.exists(self.dir)
if clone:
self.clone(*args)
return clone
def clean_checkout(repo, branch):
repo.clean('-f', '-d')
repo.reset('--hard')
repo.checkout(branch)
class Runner:
def __init__(self, cwd):
self.cwd = cwd
def __call__(self, *args, **kwargs):
kwargs['cwd'] = kwargs.get('cwd', self.cwd)
check_call(args, **kwargs)
def create_build_env():
"""Create a build environment."""
class Env:
pass
env = Env()
# Import the documentation build module.
env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(env.fmt_dir, 'doc'))
import build
env.build_dir = 'build'
env.versions = build.versions
# Virtualenv and repos are cached to speed up builds.
build.create_build_env(os.path.join(env.build_dir, 'virtualenv'))
env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt'))
return env
@contextmanager
def rewrite(filename):
class Buffer:
pass
buffer = Buffer()
if not os.path.exists(filename):
buffer.data = ''
yield buffer
return
with open(filename) as f:
buffer.data = f.read()
yield buffer
with open(filename, 'w') as f:
f.write(buffer.data)
fmt_repo_url = 'git@github.com:fmtlib/fmt'
def update_site(env):
env.fmt_repo.update(fmt_repo_url)
doc_repo = Git(os.path.join(env.build_dir, 'fmtlib.github.io'))
doc_repo.update('git@github.com:fmtlib/fmtlib.github.io')
for version in env.versions:
clean_checkout(env.fmt_repo, version)
target_doc_dir = os.path.join(env.fmt_repo.dir, 'doc')
# Remove the old theme.
for entry in os.listdir(target_doc_dir):
path = os.path.join(target_doc_dir, entry)
if os.path.isdir(path):
shutil.rmtree(path)
# Copy the new theme.
for entry in ['_static', '_templates', 'basic-bootstrap', 'bootstrap',
'conf.py', 'fmt.less']:
src = os.path.join(env.fmt_dir, 'doc', entry)
dst = os.path.join(target_doc_dir, entry)
copy = shutil.copytree if os.path.isdir(src) else shutil.copyfile
copy(src, dst)
# Rename index to contents.
contents = os.path.join(target_doc_dir, 'contents.rst')
if not os.path.exists(contents):
os.rename(os.path.join(target_doc_dir, 'index.rst'), contents)
# Fix issues in reference.rst/api.rst.
for filename in ['reference.rst', 'api.rst', 'index.rst']:
pattern = re.compile('doxygenfunction.. (bin|oct|hexu|hex)$', re.M)
with rewrite(os.path.join(target_doc_dir, filename)) as b:
b.data = b.data.replace('std::ostream &', 'std::ostream&')
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
b.data = b.data.replace('std::FILE*', 'std::FILE *')
b.data = b.data.replace('unsigned int', 'unsigned')
#b.data = b.data.replace('operator""_', 'operator"" _')
b.data = b.data.replace(
'format_to_n(OutputIt, size_t, string_view, Args&&',
'format_to_n(OutputIt, size_t, const S&, const Args&')
b.data = b.data.replace(
'format_to_n(OutputIt, std::size_t, string_view, Args&&',
'format_to_n(OutputIt, std::size_t, const S&, const Args&')
if version == ('3.0.2'):
b.data = b.data.replace(
'fprintf(std::ostream&', 'fprintf(std::ostream &')
if version == ('5.3.0'):
b.data = b.data.replace(
'format_to(OutputIt, const S&, const Args&...)',
'format_to(OutputIt, const S &, const Args &...)')
if version.startswith('5.') or version.startswith('6.'):
b.data = b.data.replace(', size_t', ', std::size_t')
if version.startswith('7.'):
b.data = b.data.replace(', std::size_t', ', size_t')
b.data = b.data.replace('join(It, It', 'join(It, Sentinel')
if version.startswith('7.1.'):
b.data = b.data.replace(', std::size_t', ', size_t')
b.data = b.data.replace('join(It, It', 'join(It, Sentinel')
b.data = b.data.replace(
'fmt::format_to(OutputIt, const S&, Args&&...)',
'fmt::format_to(OutputIt, const S&, Args&&...) -> ' +
'typename std::enable_if<enable, OutputIt>::type')
b.data = b.data.replace('aa long', 'a long')
b.data = b.data.replace('serveral', 'several')
if version.startswith('6.2.'):
b.data = b.data.replace(
'vformat(const S&, basic_format_args<' +
'buffer_context<Char>>)',
'vformat(const S&, basic_format_args<' +
'buffer_context<type_identity_t<Char>>>)')
# Fix a broken link in index.rst.
index = os.path.join(target_doc_dir, 'index.rst')
with rewrite(index) as b:
b.data = b.data.replace(
'doc/latest/index.html#format-string-syntax', 'syntax.html')
# Fix issues in syntax.rst.
index = os.path.join(target_doc_dir, 'syntax.rst')
with rewrite(index) as b:
b.data = b.data.replace(
'..productionlist:: sf\n', '.. productionlist:: sf\n ')
b.data = b.data.replace('Examples:\n', 'Examples::\n')
# Build the docs.
html_dir = os.path.join(env.build_dir, 'html')
if os.path.exists(html_dir):
shutil.rmtree(html_dir)
include_dir = env.fmt_repo.dir
if LooseVersion(version) >= LooseVersion('5.0.0'):
include_dir = os.path.join(include_dir, 'include', 'fmt')
elif LooseVersion(version) >= LooseVersion('3.0.0'):
include_dir = os.path.join(include_dir, 'fmt')
import build
build.build_docs(version, doc_dir=target_doc_dir,
include_dir=include_dir, work_dir=env.build_dir)
shutil.rmtree(os.path.join(html_dir, '.doctrees'))
# Create symlinks for older versions.
for link, target in {'index': 'contents', 'api': 'reference'}.items():
link = os.path.join(html_dir, link) + '.html'
target += '.html'
if os.path.exists(os.path.join(html_dir, target)) and \
not os.path.exists(link):
os.symlink(target, link)
# Copy docs to the website.
version_doc_dir = os.path.join(doc_repo.dir, version)
try:
shutil.rmtree(version_doc_dir)
except OSError as e:
if e.errno != errno.ENOENT:
raise
shutil.move(html_dir, version_doc_dir)
def release(args):
env = create_build_env()
fmt_repo = env.fmt_repo
branch = args.get('<branch>')
if branch is None:
branch = 'master'
if not fmt_repo.update('-b', branch, fmt_repo_url):
clean_checkout(fmt_repo, branch)
# Convert changelog from RST to GitHub-flavored Markdown and get the
# version.
changelog = 'ChangeLog.rst'
changelog_path = os.path.join(fmt_repo.dir, changelog)
import rst2md
changes, version = rst2md.convert(changelog_path)
cmakelists = 'CMakeLists.txt'
for line in fileinput.input(os.path.join(fmt_repo.dir, cmakelists),
inplace=True):
prefix = 'set(FMT_VERSION '
if line.startswith(prefix):
line = prefix + version + ')\n'
sys.stdout.write(line)
# Update the version in the changelog.
title_len = 0
for line in fileinput.input(changelog_path, inplace=True):
if line.startswith(version + ' - TBD'):
line = version + ' - ' + datetime.date.today().isoformat()
title_len = len(line)
line += '\n'
elif title_len:
line = '-' * title_len + '\n'
title_len = 0
sys.stdout.write(line)
# Add the version to the build script.
script = os.path.join('doc', 'build.py')
script_path = os.path.join(fmt_repo.dir, script)
for line in fileinput.input(script_path, inplace=True):
m = re.match(r'( *versions = )\[(.+)\]', line)
if m:
line = '{}[{}, \'{}\']\n'.format(m.group(1), m.group(2), version)
sys.stdout.write(line)
fmt_repo.checkout('-B', 'release')
fmt_repo.add(changelog, cmakelists, script)
fmt_repo.commit('-m', 'Update version')
# Build the docs and package.
run = Runner(fmt_repo.dir)
run('cmake', '.')
run('make', 'doc', 'package_source')
update_site(env)
# Create a release on GitHub.
fmt_repo.push('origin', 'release')
auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')}
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
headers=auth_headers,
data=json.dumps({'tag_name': version,
'target_commitish': 'release',
'body': changes, 'draft': True}))
if r.status_code != 201:
raise Exception('Failed to create a release ' + str(r))
id = r.json()['id']
uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases'
package = 'fmt-{}.zip'.format(version)
r = requests.post(
'{}/{}/assets?name={}'.format(uploads_url, id, package),
headers={'Content-Type': 'application/zip'} | auth_headers,
data=open('build/fmt/' + package, 'rb'))
if r.status_code != 201:
raise Exception('Failed to upload an asset ' + str(r))
if __name__ == '__main__':
args = docopt.docopt(__doc__)
if args.get('release'):
release(args)
elif args.get('site'):
update_site(create_build_env())

View File

@ -1,201 +0,0 @@
#!/usr/bin/env python3
# This script is based on
# https://github.com/rust-lang/rust/blob/master/library/core/src/unicode/printable.py
# distributed under https://github.com/rust-lang/rust/blob/master/LICENSE-MIT.
# This script uses the following Unicode tables:
# - UnicodeData.txt
from collections import namedtuple
import csv
import os
import subprocess
NUM_CODEPOINTS=0x110000
def to_ranges(iter):
current = None
for i in iter:
if current is None or i != current[1] or i in (0x10000, 0x20000):
if current is not None:
yield tuple(current)
current = [i, i + 1]
else:
current[1] += 1
if current is not None:
yield tuple(current)
def get_escaped(codepoints):
for c in codepoints:
if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '):
yield c.value
def get_file(f):
try:
return open(os.path.basename(f))
except FileNotFoundError:
subprocess.run(["curl", "-O", f], check=True)
return open(os.path.basename(f))
Codepoint = namedtuple('Codepoint', 'value class_')
def get_codepoints(f):
r = csv.reader(f, delimiter=";")
prev_codepoint = 0
class_first = None
for row in r:
codepoint = int(row[0], 16)
name = row[1]
class_ = row[2]
if class_first is not None:
if not name.endswith("Last>"):
raise ValueError("Missing Last after First")
for c in range(prev_codepoint + 1, codepoint):
yield Codepoint(c, class_first)
class_first = None
if name.endswith("First>"):
class_first = class_
yield Codepoint(codepoint, class_)
prev_codepoint = codepoint
if class_first is not None:
raise ValueError("Missing Last after First")
for c in range(prev_codepoint + 1, NUM_CODEPOINTS):
yield Codepoint(c, None)
def compress_singletons(singletons):
uppers = [] # (upper, # items in lowers)
lowers = []
for i in singletons:
upper = i >> 8
lower = i & 0xff
if len(uppers) == 0 or uppers[-1][0] != upper:
uppers.append((upper, 1))
else:
upper, count = uppers[-1]
uppers[-1] = upper, count + 1
lowers.append(lower)
return uppers, lowers
def compress_normal(normal):
# lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f
# lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff
compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)]
prev_start = 0
for start, count in normal:
truelen = start - prev_start
falselen = count
prev_start = start + count
assert truelen < 0x8000 and falselen < 0x8000
entry = []
if truelen > 0x7f:
entry.append(0x80 | (truelen >> 8))
entry.append(truelen & 0xff)
else:
entry.append(truelen & 0x7f)
if falselen > 0x7f:
entry.append(0x80 | (falselen >> 8))
entry.append(falselen & 0xff)
else:
entry.append(falselen & 0x7f)
compressed.append(entry)
return compressed
def print_singletons(uppers, lowers, uppersname, lowersname):
print(" static constexpr singleton {}[] = {{".format(uppersname))
for u, c in uppers:
print(" {{{:#04x}, {}}},".format(u, c))
print(" };")
print(" static constexpr unsigned char {}[] = {{".format(lowersname))
for i in range(0, len(lowers), 8):
print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
print(" };")
def print_normal(normal, normalname):
print(" static constexpr unsigned char {}[] = {{".format(normalname))
for v in normal:
print(" {}".format(" ".join("{:#04x},".format(i) for i in v)))
print(" };")
def main():
file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
codepoints = get_codepoints(file)
CUTOFF=0x10000
singletons0 = []
singletons1 = []
normal0 = []
normal1 = []
extra = []
for a, b in to_ranges(get_escaped(codepoints)):
if a > 2 * CUTOFF:
extra.append((a, b - a))
elif a == b - 1:
if a & CUTOFF:
singletons1.append(a & ~CUTOFF)
else:
singletons0.append(a)
elif a == b - 2:
if a & CUTOFF:
singletons1.append(a & ~CUTOFF)
singletons1.append((a + 1) & ~CUTOFF)
else:
singletons0.append(a)
singletons0.append(a + 1)
else:
if a >= 2 * CUTOFF:
extra.append((a, b - a))
elif a & CUTOFF:
normal1.append((a & ~CUTOFF, b - a))
else:
normal0.append((a, b - a))
singletons0u, singletons0l = compress_singletons(singletons0)
singletons1u, singletons1l = compress_singletons(singletons1)
normal0 = compress_normal(normal0)
normal1 = compress_normal(normal1)
print("""\
FMT_FUNC auto is_printable(uint32_t cp) -> bool {\
""")
print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
print_normal(normal0, 'normal0')
print_normal(normal1, 'normal1')
print("""\
auto lower = static_cast<uint16_t>(cp);
if (cp < 0x10000) {
return is_printable(lower, singletons0,
sizeof(singletons0) / sizeof(*singletons0),
singletons0_lower, normal0, sizeof(normal0));
}
if (cp < 0x20000) {
return is_printable(lower, singletons1,
sizeof(singletons1) / sizeof(*singletons1),
singletons1_lower, normal1, sizeof(normal1));
}\
""")
for a, b in extra:
print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b))
print("""\
return cp < 0x{:x};
}}\
""".format(NUM_CODEPOINTS))
if __name__ == '__main__':
main()

View File

@ -1,159 +0,0 @@
#!/usr/bin/env python
# reStructuredText (RST) to GitHub-flavored Markdown converter
import re, sys
from docutils import core, nodes, writers
def is_github_ref(node):
return re.match('https://github.com/.*/(issues|pull)/.*', node['refuri'])
class Translator(nodes.NodeVisitor):
def __init__(self, document):
nodes.NodeVisitor.__init__(self, document)
self.output = ''
self.indent = 0
self.preserve_newlines = False
def write(self, text):
self.output += text.replace('\n', '\n' + ' ' * self.indent)
def visit_document(self, node):
pass
def depart_document(self, node):
pass
def visit_section(self, node):
pass
def depart_section(self, node):
# Skip all sections except the first one.
raise nodes.StopTraversal
def visit_title(self, node):
self.version = re.match(r'(\d+\.\d+\.\d+).*', node.children[0]).group(1)
raise nodes.SkipChildren
def visit_title_reference(self, node):
raise Exception(node)
def depart_title(self, node):
pass
def visit_Text(self, node):
if not self.preserve_newlines:
node = node.replace('\n', ' ')
self.write(node)
def depart_Text(self, node):
pass
def visit_bullet_list(self, node):
pass
def depart_bullet_list(self, node):
pass
def visit_list_item(self, node):
self.write('* ')
self.indent += 2
def depart_list_item(self, node):
self.indent -= 2
self.write('\n\n')
def visit_paragraph(self, node):
self.write('\n\n')
def depart_paragraph(self, node):
pass
def visit_reference(self, node):
if not is_github_ref(node):
self.write('[')
def depart_reference(self, node):
if not is_github_ref(node):
self.write('](' + node['refuri'] + ')')
def visit_target(self, node):
pass
def depart_target(self, node):
pass
def visit_literal(self, node):
self.write('`')
def depart_literal(self, node):
self.write('`')
def visit_literal_block(self, node):
self.write('\n\n```')
if 'c++' in node['classes']:
self.write('c++')
self.write('\n')
self.preserve_newlines = True
def depart_literal_block(self, node):
self.write('\n```\n')
self.preserve_newlines = False
def visit_inline(self, node):
pass
def depart_inline(self, node):
pass
def visit_image(self, node):
self.write('![](' + node['uri'] + ')')
def depart_image(self, node):
pass
def write_row(self, row, widths):
for i, entry in enumerate(row):
text = entry[0][0] if len(entry) > 0 else ''
if i != 0:
self.write('|')
self.write('{:{}}'.format(text, widths[i]))
self.write('\n')
def visit_table(self, node):
table = node.children[0]
colspecs = table[:-2]
thead = table[-2]
tbody = table[-1]
widths = [int(cs['colwidth']) for cs in colspecs]
sep = '|'.join(['-' * w for w in widths]) + '\n'
self.write('\n\n')
self.write_row(thead[0], widths)
self.write(sep)
for row in tbody:
self.write_row(row, widths)
raise nodes.SkipChildren
def depart_table(self, node):
pass
class MDWriter(writers.Writer):
"""GitHub-flavored markdown writer"""
supported = ('md',)
"""Formats this writer supports."""
def translate(self):
translator = Translator(self.document)
self.document.walkabout(translator)
self.output = (translator.output, translator.version)
def convert(rst_path):
"""Converts RST file to Markdown."""
return core.publish_file(source_path=rst_path, writer=MDWriter())
if __name__ == '__main__':
convert(sys.argv[1])

View File

@ -1,7 +0,0 @@
# Sphinx configuration for readthedocs.
import os, sys
master_doc = 'index'
html_theme = 'theme'
html_theme_path = ["."]

View File

@ -1,2 +0,0 @@
If you are not redirected automatically, follow the
`link to the fmt documentation <https://fmt.dev/latest/>`_.

View File

@ -1,17 +0,0 @@
{% extends "basic/layout.html" %}
{% block extrahead %}
<meta charset="UTF-8">
<meta http-equiv="refresh" content="1;url=https://fmt.dev/latest/">
<script type="text/javascript">
window.location.href = "https://fmt.dev/latest/"
</script>
<title>Page Redirection</title>
{% endblock %}
{% block document %}
If you are not redirected automatically, follow the <a href='https://fmt.dev/latest/'>link to the fmt documentation</a>.
{% endblock %}
{% block footer %}
{% endblock %}

View File

@ -1,2 +0,0 @@
[theme]
inherit = basic

View File

@ -60,27 +60,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
StkId o = ci->func + idx;
api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
if (o >= L->top) return &G(L)->nilvalue;
StkId o = ci->func.p + idx;
api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o);
}
else if (!ispseudo(idx)) { /* negative index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return s2v(L->top + idx);
api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
return s2v(L->top.p + idx);
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttisCclosure(s2v(ci->func))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func));
if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
else { /* light C function or Lua function (through a hook)?) */
api_check(L, ttislcf(s2v(ci->func)), "caller not a C function");
api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */
}
}
@ -94,14 +95,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
StkId o = ci->func + idx;
api_check(L, o < L->top, "invalid index");
StkId o = ci->func.p + idx;
api_check(L, o < L->top.p, "invalid index");
return o;
}
else { /* non-positive index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
api_check(L, !ispseudo(idx), "invalid index");
return L->top + idx;
return L->top.p + idx;
}
}
@ -112,17 +114,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L);
ci = L->ci;
api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */
if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */
else { /* no; need to grow stack */
int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
res = 0; /* no */
else /* try to grow stack */
res = luaD_growstack(L, n, 0);
}
if (res && ci->top < L->top + n)
ci->top = L->top + n; /* adjust frame top */
else /* need to grow stack */
res = luaD_growstack(L, n, 0);
if (res && ci->top.p < L->top.p + n)
ci->top.p = L->top.p + n; /* adjust frame top */
lua_unlock(L);
return res;
}
@ -134,11 +131,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
from->top.p -= n;
for (i = 0; i < n; i++) {
setobjs2s(to, to->top, from->top + i);
to->top++; /* stack already checked by previous 'api_check' */
setobjs2s(to, to->top.p, from->top.p + i);
to->top.p++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@ -172,12 +169,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
: cast_int(L->top - L->ci->func) + idx;
: cast_int(L->top.p - L->ci->func.p) + idx;
}
LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1));
return cast_int(L->top.p - (L->ci->func.p + 1));
}
@ -187,24 +184,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */
lua_lock(L);
ci = L->ci;
func = ci->func;
func = ci->func.p;
if (idx >= 0) {
api_check(L, idx <= ci->top - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top;
api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--)
setnilvalue(s2v(L->top++)); /* clear new slots */
setnilvalue(s2v(L->top.p++)); /* clear new slots */
}
else {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */
}
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
newtop = L->top + diff;
if (diff < 0 && L->tbclist >= newtop) {
api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
newtop = L->top.p + diff;
if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0);
newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
}
L->top = newtop; /* correct top only after closing any upvalue */
L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L);
}
@ -213,10 +210,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level;
lua_lock(L);
level = index2stack(L, idx);
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level");
luaF_close(L, level, CLOSEKTOP, 0);
level = index2stack(L, idx); /* stack may be moved */
level = luaF_close(L, level, CLOSEKTOP, 0);
setnilvalue(s2v(level));
lua_unlock(L);
}
@ -245,7 +241,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m;
lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */
t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@ -264,7 +260,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
lua_unlock(L);
@ -273,7 +269,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
setobj2s(L, L->top, index2value(L, idx));
setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L);
lua_unlock(L);
}
@ -342,12 +338,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1);
setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
L->top--; /* remove second operand */
luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
L->top.p--; /* remove second operand */
lua_unlock(L);
}
@ -373,7 +369,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
size_t sz = luaO_str2num(s, s2v(L->top));
size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0)
api_incr_top(L);
return sz;
@ -500,7 +496,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L);
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@ -508,7 +504,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
setfltvalue(s2v(L->top), n);
setfltvalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@ -516,7 +512,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L);
setivalue(s2v(L->top), n);
setivalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@ -531,7 +527,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts);
setsvalue2s(L, L->top.p, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@ -542,11 +538,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L);
if (s == NULL)
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
else {
TString *ts;
ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts);
setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
@ -583,7 +579,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
setfvalue(s2v(L->top), fn);
setfvalue(s2v(L->top.p), fn);
api_incr_top(L);
}
else {
@ -592,13 +588,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
L->top.p -= n;
while (n--) {
setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */
lua_assert(iswhite(cl));
}
setclCvalue(L, s2v(L->top), cl);
setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L);
luaC_checkGC(L);
}
@ -609,9 +605,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L);
if (b)
setbtvalue(s2v(L->top));
setbtvalue(s2v(L->top.p));
else
setbfvalue(s2v(L->top));
setbfvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@ -619,7 +615,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L);
setpvalue(s2v(L->top), p);
setpvalue(s2v(L->top.p), p);
api_incr_top(L);
lua_unlock(L);
}
@ -627,7 +623,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L);
setthvalue(L, s2v(L->top), L);
setthvalue(L, s2v(L->top.p), L);
api_incr_top(L);
lua_unlock(L);
return (G(L)->mainthread == L);
@ -644,16 +640,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot);
setobj2s(L, L->top.p, slot);
api_incr_top(L);
}
else {
setsvalue2s(L, L->top, str);
setsvalue2s(L, L->top.p, str);
api_incr_top(L);
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
}
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
@ -680,13 +676,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
setobj2s(L, L->top - 1, slot);
if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
setobj2s(L, L->top.p - 1, slot);
}
else
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
@ -702,27 +698,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot);
setobj2s(L, L->top.p, slot);
}
else {
TValue aux;
setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot);
luaV_finishget(L, t, &aux, L->top.p, slot);
}
api_incr_top(L);
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
else
setobj2s(L, L->top, val);
setobj2s(L, L->top.p, val);
api_incr_top(L);
lua_unlock(L);
return ttype(s2v(L->top - 1));
return ttype(s2v(L->top.p - 1));
}
@ -739,8 +735,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
val = luaH_get(t, s2v(L->top - 1));
L->top--; /* remove key */
val = luaH_get(t, s2v(L->top.p - 1));
L->top.p--; /* remove key */
return finishrawget(L, val);
}
@ -767,7 +763,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
t = luaH_new(L);
sethvalue2s(L, L->top, t);
sethvalue2s(L, L->top.p, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
@ -794,7 +790,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break;
}
if (mt != NULL) {
sethvalue2s(L, L->top, mt);
sethvalue2s(L, L->top.p, mt);
api_incr_top(L);
res = 1;
}
@ -810,12 +806,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) {
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
t = LUA_TNONE;
}
else {
setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top));
setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top.p));
}
api_incr_top(L);
lua_unlock(L);
@ -835,14 +831,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
L->top--; /* pop value */
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
L->top.p--; /* pop value */
}
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
L->top -= 2; /* pop value and key */
luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
L->top.p -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
@ -862,12 +858,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 2);
t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
L->top -= 2; /* pop index and value */
luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
L->top.p -= 2; /* pop index and value */
lua_unlock(L);
}
@ -885,14 +881,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else {
TValue aux;
setivalue(&aux, n);
luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
}
L->top--; /* pop value */
L->top.p--; /* pop value */
lua_unlock(L);
}
@ -902,16 +898,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L);
api_checknelems(L, n);
t = gettable(L, idx);
luaH_set(L, t, key, s2v(L->top - 1));
luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
L->top -= n;
luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top.p -= n;
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
aux_rawset(L, idx, s2v(L->top - 2), 2);
aux_rawset(L, idx, s2v(L->top.p - 2), 2);
}
@ -927,9 +923,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
luaH_setint(L, t, n, s2v(L->top - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
L->top--;
luaH_setint(L, t, n, s2v(L->top.p - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top.p--;
lua_unlock(L);
}
@ -940,11 +936,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L);
api_checknelems(L, 1);
obj = index2value(L, objindex);
if (ttisnil(s2v(L->top - 1)))
if (ttisnil(s2v(L->top.p - 1)))
mt = NULL;
else {
api_check(L, ttistable(s2v(L->top - 1)), "table expected");
mt = hvalue(s2v(L->top - 1));
api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
mt = hvalue(s2v(L->top.p - 1));
}
switch (ttype(obj)) {
case LUA_TTABLE: {
@ -968,7 +964,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break;
}
}
L->top--;
L->top.p--;
lua_unlock(L);
return 1;
}
@ -984,11 +980,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else {
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1;
}
L->top--;
L->top.p--;
lua_unlock(L);
return res;
}
@ -1000,7 +996,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
api_check(L, (nr) == LUA_MULTRET \
|| (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size")
@ -1013,7 +1010,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
func = L->top - (nargs+1);
func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
@ -1061,7 +1058,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@ -1096,12 +1093,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt);
setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt);
}
}
@ -1115,7 +1112,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o;
lua_lock(L);
api_checknelems(L, 1);
o = s2v(L->top - 1);
o = s2v(L->top.p - 1);
if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip);
else
@ -1241,7 +1238,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) {
TValue *errobj;
lua_lock(L);
errobj = s2v(L->top - 1);
errobj = s2v(L->top.p - 1);
api_checknelems(L, 1);
/* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@ -1259,12 +1256,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
more = luaH_next(L, t, L->top - 1);
more = luaH_next(L, t, L->top.p - 1);
if (more) {
api_incr_top(L);
}
else /* no more elements */
L->top -= 1; /* remove key */
L->top.p -= 1; /* remove key */
lua_unlock(L);
return more;
}
@ -1276,7 +1273,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L);
o = index2stack(L, idx);
nresults = L->ci->nresults;
api_check(L, L->tbclist < o, "given index below or equal a marked one");
api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */
@ -1291,7 +1288,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0)
luaV_concat(L, n);
else { /* nothing to concatenate */
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L);
}
luaC_checkGC(L);
@ -1303,7 +1300,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
luaV_objlen(L, L->top, t);
luaV_objlen(L, L->top.p, t);
api_incr_top(L);
lua_unlock(L);
}
@ -1348,7 +1345,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue);
setuvalue(L, s2v(L->top), u);
setuvalue(L, s2v(L->top.p), u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@ -1374,7 +1371,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */
*val = f->upvals[n-1]->v;
*val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name);
@ -1390,7 +1387,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) {
setobj2s(L, L->top, val);
setobj2s(L, L->top.p, val);
api_incr_top(L);
}
lua_unlock(L);
@ -1408,8 +1405,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner);
if (name) {
L->top--;
setobj(L, val, s2v(L->top));
L->top.p--;
setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val);
}
lua_unlock(L);

View File

@ -12,23 +12,26 @@
#include "lstate.h"
/* Increments 'L->top', checking for stack overflows */
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
/* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top.p++; \
api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top').
** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
#define api_checknelems(L,n) \
api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack")
/*

View File

@ -526,13 +526,14 @@ static void newbox (lua_State *L) {
/*
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
** bytes.
** bytes. (The test for "not big enough" also gets the case when the
** computation of 'newsize' overflows.)
*/
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
size_t newsize = B->size * 2; /* double buffer size */
size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large");
if (newsize < B->n + sz) /* double is not big enough? */
if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz;
return newsize;
}
@ -611,7 +612,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will
** be) bellow the string being added to the buffer. (Box creation can
** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.)
*/
@ -739,17 +740,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
}
static int skipBOM (LoadF *lf) {
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
int c;
lf->n = 0;
do {
c = getc(lf->f);
if (c == EOF || c != *(const unsigned char *)p++) return c;
lf->buff[lf->n++] = c; /* to be read by the parser */
} while (*p != '\0');
lf->n = 0; /* prefix matched; discard it */
return getc(lf->f); /* return next character */
/*
** Skip an optional BOM at the start of a stream. If there is an
** incomplete BOM (the first character is correct but the rest is
** not), returns the first character anyway to force an error
** (as no chunk can start with 0xEF).
*/
static int skipBOM (FILE *f) {
int c = getc(f); /* read first character */
if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
return getc(f); /* ignore BOM and return next char */
else /* no (valid) BOM */
return c; /* return first character */
}
@ -760,13 +762,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
static int skipcomment (LoadF *lf, int *cp) {
int c = *cp = skipBOM(lf);
static int skipcomment (FILE *f, int *cp) {
int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
c = getc(f);
} while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */
*cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
@ -788,12 +790,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
if (skipcomment(&lf, &c)) /* read initial portion */
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(&lf, &c); /* re-read initial portion */
lf.n = 0;
if (skipcomment(lf.f, &c)) /* read initial portion */
lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
if (c == LUA_SIGNATURE[0]) { /* binary file? */
lf.n = 0; /* remove possible newline */
if (filename) { /* "real" file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(lf.f, &c); /* re-read initial portion */
}
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */

View File

@ -1351,6 +1351,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
}
/*
** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
lua_assert(baser <= opr &&
((baser == OPR_ADD && opr <= OPR_SHR) ||
(baser == OPR_LT && opr <= OPR_LE)));
return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
}
/*
** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode unopr2op (UnOpr opr) {
return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
cast_int(OP_UNM));
}
/*
** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
*/
l_sinline TMS binopr2TM (BinOpr opr) {
lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
}
/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
@ -1389,12 +1418,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over
** two registers.
*/
static void codebinexpval (FuncState *fs, OpCode op,
static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
/* 'e1' must be already in a register or it is a constant */
lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR);
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
cast(TMS, (op - OP_ADD) + TM_ADD));
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
}
@ -1410,6 +1442,18 @@ static void codebini (FuncState *fs, OpCode op,
}
/*
** Code binary operators with K operand.
*/
static void codebinK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = binopr2TM(opr);
int v2 = e2->u.info; /* K index */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
/* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value.
*/
@ -1437,24 +1481,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
}
/*
** Code binary operators with no constant operand.
*/
static void codebinNoK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
}
/*
** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands.
*/
static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = cast(TMS, opr + TM_ADD);
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
int v2 = e2->u.info; /* K index */
OpCode op = cast(OpCode, opr + OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
else { /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADD);
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, op, e1, e2, line); /* use standard operators */
}
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
codebinK(fs, opr, e1, e2, flip, line);
else /* 'e2' is neither an immediate nor a K operand */
codebinNoK(fs, opr, e1, e2, flip, line);
}
@ -1471,35 +1518,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1;
}
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else
codearith(fs, op, e1, e2, flip, line);
}
/*
** Code bitwise operations; they are all associative, so the function
** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand).
*/
static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int flip = 0;
int v2;
OpCode op;
if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
if (e1->k == VKINT) {
swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1;
}
else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */
op = cast(OpCode, opr + OP_ADD);
codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */
return;
}
v2 = e2->u.info; /* index in K array */
op = cast(OpCode, opr + OP_ADDK);
lua_assert(ttisinteger(&fs->f->k[v2]));
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
cast(TMS, opr + TM_ADD));
if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
codebinK(fs, opr, e1, e2, flip, line);
else /* no constants */
codebinNoK(fs, opr, e1, e2, flip, line);
}
@ -1507,25 +1546,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float.
*/
static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2;
int im;
int isfloat = 0;
OpCode op;
if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1);
r2 = im;
op = cast(OpCode, (op - OP_LT) + OP_LTI);
op = binopr2op(opr, OPR_LT, OP_LTI);
}
else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2);
r2 = im;
op = (op == OP_LT) ? OP_GTI : OP_GEI;
op = binopr2op(opr, OPR_LT, OP_GTI);
}
else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2);
op = binopr2op(opr, OPR_LT, OP_LT);
}
freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@ -1551,7 +1592,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI;
r2 = im; /* immediate operand */
}
else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */
else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK;
r2 = e2->u.info; /* constant index */
}
@ -1568,16 +1609,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/*
** Apply prefix operation 'op' to expression 'e'.
*/
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e);
switch (op) {
switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef))
if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break;
/* else */ /* FALLTHROUGH */
case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
codeunexpval(fs, unopr2op(opr), e, line);
break;
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
@ -1611,7 +1652,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v);
/* else keep numeral, which may be folded with 2nd operand */
/* else keep numeral, which may be folded or used as an immediate
operand */
break;
}
case OPR_EQ: case OPR_NE: {
@ -1706,30 +1748,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */;
}
else /* regular case (two registers) */
codebinexpval(fs, OP_SHL, e1, e2, line);
codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_SHR: {
if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */
codebinexpval(fs, OP_SHR, e1, e2, line);
codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2);
break;
}
case OPR_LT: case OPR_LE: {
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
codeorder(fs, op, e1, e2);
break;
}
case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2);
codeorder(fs, op, e1, e2);
opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
} /* FALLTHROUGH */
case OPR_LT: case OPR_LE: {
codeorder(fs, opr, e1, e2);
break;
}
default: lua_assert(0);

View File

@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */
stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */
}
@ -172,7 +172,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
status = lua_resetthread(co);
status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;

View File

@ -182,10 +182,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
if (clLvalue(s2v(ci->func))->p->is_vararg) {
if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */
*pos = ci->func - nextra - (n + 1);
*pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */
}
}
@ -194,7 +194,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
StkId base = ci->func + 1;
StkId base = ci->func.p + 1;
const char *name = NULL;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
@ -203,7 +203,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)";
@ -221,16 +221,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, L->top, pos);
setobjs2s(L, L->top.p, pos);
api_incr_top(L);
}
}
@ -245,8 +245,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */
setobjs2s(L, pos, L->top.p - 1);
L->top.p--; /* pop value */
}
lua_unlock(L);
return name;
@ -289,7 +289,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
setnilvalue(s2v(L->top));
setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
@ -298,7 +298,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top, t); /* push it on stack */
sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
if (!p->is_vararg) /* regular function? */
@ -388,20 +388,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L);
if (*what == '>') {
ci = NULL;
func = s2v(L->top - 1);
func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
L->top.p--; /* pop function */
}
else {
ci = ar->i_ci;
func = s2v(ci->func);
func = s2v(ci->func.p);
lua_assert(ttisfunction(func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
setobj2s(L, L->top, func);
setobj2s(L, L->top.p, func);
api_incr_top(L);
}
if (strchr(what, 'L'))
@ -656,18 +656,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/*
** Check whether pointer 'o' points to some value in the stack
** frame of the current function. Because 'o' may not point to a
** value in this stack, we cannot compare it with the region
** boundaries (undefined behaviour in ISO C).
** Check whether pointer 'o' points to some value in the stack frame of
** the current function and, if so, returns its index. Because 'o' may
** not point to a value in this stack, we cannot compare it with the
** region boundaries (undefined behavior in ISO C).
*/
static int isinstack (CallInfo *ci, const TValue *o) {
StkId pos;
for (pos = ci->func + 1; pos < ci->top; pos++) {
if (o == s2v(pos))
return 1;
static int instack (CallInfo *ci, const TValue *o) {
int pos;
StkId base = ci->func.p + 1;
for (pos = 0; base + pos < ci->top.p; pos++) {
if (o == s2v(base + pos))
return pos;
}
return 0; /* not found */
return -1; /* not found */
}
@ -681,7 +682,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) {
if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
@ -708,9 +709,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */
kind = getobjname(ci_func(ci)->p, currentpc(ci),
cast_int(cast(StkId, o) - (ci->func + 1)), &name);
if (!kind) { /* not an upvalue? */
int reg = instack(ci, o); /* try a register */
if (reg >= 0) /* is 'o' a register? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
}
}
return formatvarinfo(L, kind, name);
}
@ -807,10 +810,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc)));
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top - 2, 1); /* call it */
setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
setobjs2s(L, L->top.p - 1, errfunc); /* push function */
L->top.p++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
@ -824,8 +827,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */
if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
L->top.p--;
}
luaG_errormsg(L);
}
@ -842,7 +848,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */
return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
int delta = 0; /* line diference */
int delta = 0; /* line difference */
int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
@ -869,7 +875,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct
** 'L->top' before calling anything that can run the GC.
** 'L->top.p' before calling anything that can run the GC.
*/
int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci;
@ -892,7 +898,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top = ci->top; /* correct top */
L->top.p = ci->top.p; /* correct top */
if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) {

View File

@ -15,7 +15,7 @@
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func)))
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount)

View File

@ -104,11 +104,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
}
default: {
lua_assert(errorstatus(errcode)); /* real error */
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break;
}
}
L->top = oldtop + 1;
L->top.p = oldtop + 1;
}
@ -121,7 +121,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation
** ===================================================================
*/
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/*
** Change all pointers to the stack into offsets.
*/
static void relstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
L->top = (L->top - oldstack) + newstack;
L->tbclist = (L->tbclist - oldstack) + newstack;
L->top.offset = savestack(L, L->top.p);
L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v = s2v((uplevel(up) - oldstack) + newstack);
up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + newstack;
ci->func = (ci->func - oldstack) + newstack;
ci->top.offset = savestack(L, ci->top.p);
ci->func.offset = savestack(L, ci->func.p);
}
}
/*
** Change back all offsets into pointers.
*/
static void correctstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
L->top.p = restorestack(L, L->top.offset);
L->tbclist.p = restorestack(L, L->tbclist.offset);
for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top.p = restorestack(L, ci->top.offset);
ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
}
@ -176,44 +198,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/*
** Reallocate the stack to a new size, correcting all pointers into
** it. (There are pointers to a stack from its upvalues, from its list
** of call infos, plus a few individual pointers.) The reallocation is
** done in two steps (allocation + free) because the correction must be
** done while both addresses (the old stack and the new one) are valid.
** (In ISO C, any pointer use after the pointer has been deallocated is
** undefined behavior.)
** Reallocate the stack to a new size, correcting all pointers into it.
** In ISO C, any pointer use after the pointer has been deallocated is
** undefined behavior. So, before the reallocation, all pointers are
** changed to offsets, and after the reallocation they are changed back
** to pointers. As during the reallocation the pointers are invalid, the
** reallocation cannot run emergency collections.
**
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L);
int i;
StkId newstack = luaM_reallocvector(L, NULL, 0,
newsize + EXTRA_STACK, StackValue);
StkId newstack;
int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
relstack(L); /* change pointers to offsets */
G(L)->gcstopem = 1; /* stop emergency collection */
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
newsize + EXTRA_STACK, StackValue);
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
correctstack(L); /* change offsets back to pointers */
if (raiseerror)
luaM_error(L);
else return 0; /* do not raise an error */
}
/* number of elements to be copied to the new stack */
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
memcpy(newstack, L->stack, i * sizeof(StackValue));
for (; i < newsize + EXTRA_STACK; i++)
L->stack.p = newstack;
correctstack(L); /* change offsets back to pointers */
L->stack_last.p = L->stack.p + newsize;
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
correctstack(L, L->stack, newstack);
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
L->stack = newstack;
L->stack_last = L->stack + newsize;
return 1;
}
/*
** Try to grow the stack by at least 'n' elements. when 'raiseerror'
** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors.
*/
int luaD_growstack (lua_State *L, int n, int raiseerror) {
@ -227,35 +250,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */
}
else {
else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */
int needed = cast_int(L->top - L->stack) + n;
int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */
newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror);
else { /* stack overflow */
/* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror)
luaG_runerror(L, "stack overflow");
return 0;
}
}
/* else stack overflow */
/* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror)
luaG_runerror(L, "stack overflow");
return 0;
}
/*
** Compute how much of the stack is being used, by computing the
** maximum top of all call frames in the stack and the current top.
*/
static int stackinuse (lua_State *L) {
CallInfo *ci;
int res;
StkId lim = L->top;
StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
if (lim < ci->top) lim = ci->top;
if (lim < ci->top.p) lim = ci->top.p;
}
lua_assert(lim <= L->stack_last);
res = cast_int(lim - L->stack) + 1; /* part of stack in use */
lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */
return res;
@ -273,17 +299,13 @@ static int stackinuse (lua_State *L) {
*/
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int nsize = inuse * 2; /* proposed new size */
int max = inuse * 3; /* maximum "reasonable" size */
if (max > LUAI_MAXSTACK) {
max = LUAI_MAXSTACK; /* respect stack limit */
if (nsize > LUAI_MAXSTACK)
nsize = LUAI_MAXSTACK;
}
int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
/* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
}
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */
@ -292,7 +314,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
L->top++;
L->top.p++;
}
/* }================================================================== */
@ -309,8 +331,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED;
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar;
ar.event = event;
ar.currentline = line;
@ -320,11 +342,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer;
}
if (isLua(ci) && L->top < ci->top)
L->top = ci->top; /* protect entire activation register */
if (isLua(ci) && L->top.p < ci->top.p)
L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
if (ci->top < L->top + LUA_MINSTACK)
ci->top = L->top + LUA_MINSTACK;
if (ci->top.p < L->top.p + LUA_MINSTACK)
ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask;
lua_unlock(L);
@ -332,8 +354,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
ci->top = restorestack(L, ci_top);
L->top = restorestack(L, top);
ci->top.p = restorestack(L, ci_top);
L->top.p = restorestack(L, top);
ci->callstatus &= ~mask;
}
}
@ -364,7 +386,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/
static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
StkId firstres = L->top - nres; /* index of first result */
StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */
int ftransfer;
if (isLua(ci)) {
@ -372,10 +394,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1;
}
ci->func += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func);
ci->func.p += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
ci->func -= delta;
ci->func.p -= delta;
}
if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@ -394,9 +416,9 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) {
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */
for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1);
L->top++; /* stack space pre-allocated by the caller */
L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func;
}
@ -413,28 +435,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i;
switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */
L->top = res;
L->top.p = res;
return;
case 1: /* one value needed */
if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */
setobjs2s(L, res, L->top - nres); /* move it to proper place */
L->top = res + 1;
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
L->top.p = res + 1;
return;
case LUA_MULTRET:
wanted = nres; /* we want all results */
break;
default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres;
luaF_close(L, res, CLOSEKTOP, 1);
res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET;
if (L->hookmask) /* if needed, call hook after '__close's */
if (L->hookmask) { /* if needed, call hook after '__close's */
ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres);
res = restorestack(L, savedres); /* close and hook can move stack */
res = restorestack(L, savedres); /* hook can move stack */
}
wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */
@ -442,14 +465,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break;
}
/* generic case */
firstresult = L->top - nres; /* index of first result */
firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i));
L->top = res + wanted; /* top points after the last result */
L->top.p = res + wanted; /* top points after the last result */
}
@ -464,7 +487,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres);
/* move results to proper place */
moveresults(L, ci->func, nres, wanted);
moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@ -479,10 +502,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */
ci->func = func;
ci->func.p = func;
ci->nresults = nret;
ci->callstatus = mask;
ci->top = top;
ci->top.p = top;
return ci;
}
@ -496,10 +519,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
L->top + LUA_MINSTACK);
lua_assert(ci->top <= L->stack_last);
L->top.p + LUA_MINSTACK);
lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1;
int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
@ -531,17 +554,17 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams;
int i;
checkstackGCp(L, fsize - delta, func);
ci->func -= delta; /* restore 'func' (if vararg) */
ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i);
func = ci->func; /* moved-down function */
setobjs2s(L, ci->func.p + i, func + i);
func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
ci->top = func + 1 + fsize; /* top for new function */
lua_assert(ci->top <= L->stack_last);
ci->top.p = func + 1 + fsize; /* top for new function */
lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
L->top = func + narg1; /* set top */
L->top.p = func + narg1; /* set top */
return -1;
}
default: { /* not a function */
@ -574,15 +597,15 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */
CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p;
int narg = cast_int(L->top - func) - 1; /* number of real arguments */
int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last);
setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
lua_assert(ci->top.p <= L->stack_last.p);
return ci;
}
default: { /* not a function */
@ -598,12 +621,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls).
** This function can be called with some use of EXTRA_STACK, so it should
** check the stack before doing anything else. 'luaD_precall' already
** does that.
*/
l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci;
L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L);
}
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */
@ -651,8 +679,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */
StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
luaF_close(L, func, status, 1); /* can yield or raise an error */
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
func = luaF_close(L, func, status, 1); /* can yield or raise an error */
luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */
@ -740,8 +767,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.)
*/
static int resume_error (lua_State *L, const char *msg, int narg) {
L->top -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
L->top.p -= narg; /* remove args from the stack */
setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
lua_unlock(L);
return LUA_ERRRUN;
@ -757,7 +784,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/
static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */
StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@ -765,7 +792,7 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */
L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}
else { /* 'common' yield */
@ -808,7 +835,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
else if (L->top - (L->ci->func + 1) == nargs) /* no function? */
else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs);
}
else if (L->status != LUA_YIELD) /* ended with errors? */
@ -826,11 +853,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */
L->ci->top = L->top;
luaD_seterrorobj(L, status, L->top.p); /* push error message */
L->ci->top.p = L->top.p;
}
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
: cast_int(L->top - (L->ci->func + 1));
: cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L);
return status;
}
@ -985,7 +1012,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);

View File

@ -8,6 +8,7 @@
#define ldo_h
#include "llimits.h"
#include "lobject.h"
#include "lstate.h"
#include "lzio.h"
@ -23,7 +24,7 @@
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
if (l_unlikely(L->stack_last - L->top <= (n))) \
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
@ -32,11 +33,18 @@
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@ -58,7 +66,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);

View File

@ -10,6 +10,7 @@
#include "lprefix.h"
#include <limits.h>
#include <stddef.h>
#include "lua.h"
@ -55,8 +56,11 @@ static void dumpByte (DumpState *D, int y) {
}
/* dumpInt Buff Size */
#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
/*
** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
** rounds up the division.)
*/
#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS];

View File

@ -50,8 +50,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
uv->v = &uv->u.value; /* make it closed */
setnilvalue(uv->v);
uv->v.p = &uv->u.value; /* make it closed */
setnilvalue(uv->v.p);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv);
}
@ -62,12 +62,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'.
**/
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
UpVal *next = *prev;
uv->v = s2v(level); /* current value lives in the stack */
uv->tbc = tbc;
uv->v.p = s2v(level); /* current value lives in the stack */
uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev;
if (next)
@ -96,7 +95,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next;
}
/* not found: create a new upvalue after 'pp' */
return newupval(L, 0, level, pp);
return newupval(L, level, pp);
}
@ -106,12 +105,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.)
*/
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
StkId top = L->top;
StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
L->top = top + 3; /* add function and arguments */
L->top.p = top + 3; /* add function and arguments */
if (yy)
luaD_call(L, top, 0);
else
@ -126,7 +125,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
int idx = cast_int(level - L->ci->func); /* variable index */
int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@ -160,23 +159,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.)
*/
#define MAXDELTA \
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/*
** Insert a variable in the list of to-be-closed variables.
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
lua_assert(level > L->tbclist);
lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */
while (cast_uint(level - L->tbclist) > MAXDELTA) {
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist->tbclist.delta = 0;
while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist.p->tbclist.delta = 0;
}
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
L->tbclist = level;
level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
L->tbclist.p = level;
}
@ -196,10 +195,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
lua_assert(uplevel(uv) < L->top);
lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
setobj(L, slot, uv->v); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */
setobj(L, slot, uv->v.p); /* move value to upvalue slot */
uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
@ -209,31 +208,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/*
** Remove firt element from the tbclist plus its dummy nodes.
** Remove first element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
StkId tbc = L->tbclist;
StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
while (tbc > L->stack && tbc->tbclist.delta == 0)
while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
L->tbclist = tbc;
L->tbclist.p = tbc;
}
/*
** Close all upvalues and to-be-closed variables up to the given stack
** level.
** level. Return restored 'level'.
*/
void luaF_close (lua_State *L, StkId level, int status, int yy) {
StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist; /* get variable index */
while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
return level;
}

View File

@ -29,10 +29,10 @@
#define MAXUPVAL 255
#define upisopen(up) ((up)->v != &(up)->u.value)
#define upisopen(up) ((up)->v.p != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/*
@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

View File

@ -252,12 +252,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/*
** create a new collectable object (with given type and size) and link
** it to 'allgc' list.
** create a new collectable object (with given type, size, and offset)
** and link it to 'allgc' list.
*/
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
@ -265,6 +266,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o;
}
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return luaC_newobjdt(L, tt, sz, 0);
}
/* }====================================================== */
@ -301,7 +307,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */
else
set2black(uv); /* closed upvalues are visited here */
markvalue(g, uv->v); /* mark its content */
markvalue(g, uv->v.p); /* mark its content */
break;
}
case LUA_VUSERDATA: {
@ -376,7 +382,7 @@ static int remarkupvals (global_State *g) {
work++;
if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv));
markvalue(g, uv->v); /* mark its value */
markvalue(g, uv->v.p); /* mark its value */
}
}
}
@ -620,19 +626,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/
static int traversethread (global_State *g, lua_State *th) {
UpVal *uv;
StkId o = th->stack;
StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL)
return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */
for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
for (; o < th->stack_last + EXTRA_STACK; o++)
for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@ -892,7 +898,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0);
luaD_callnoyield(L, L->top.p - 2, 0);
}
@ -909,16 +915,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */
setobj2s(L, L->top++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */
setobj2s(L, L->top.p++, tm); /* push finalizer... */
setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc");
L->top--; /* pops error object */
L->top.p--; /* pops error object */
}
}
}
@ -1041,7 +1047,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** =======================================================
*/
static void setpause (global_State *g);
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/*
@ -1285,6 +1309,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
}
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/*
** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables
@ -1297,6 +1330,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g);
setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs;
}
@ -1342,15 +1376,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
}
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/*
** Does a major collection after last collection was a "bad collection".
**
@ -1422,8 +1447,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major
collection; keep doing minor collections */
setminordebt(g);
collection; keep doing minor collections. */
lua_assert(g->lastatomic == 0);
}
else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */
@ -1449,26 +1474,6 @@ static void genstep (lua_State *L, global_State *g) {
*/
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object
@ -1676,12 +1681,15 @@ static void incstep (lua_State *L, global_State *g) {
}
/*
** performs a basic GC step if collector is running
** Performs a basic GC step if collector is running. (If collector is
** not running, set a reasonable debt to avoid it being called at
** every single check.)
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
lua_assert(!g->gcemergency);
if (gcrunning(g)) { /* running? */
if (!gcrunning(g)) /* not running? */
luaE_setdebt(g, -2000);
else {
if(isdecGCmodegen(g))
genstep(L, g);
else

View File

@ -172,24 +172,27 @@
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_barrier(L,p,v) ( \
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
#define luaC_objbarrierback(L,p,o) ( \
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);

View File

@ -128,7 +128,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
** is a TValue readly available. Later, the code generation can change
** is a TValue readily available. Later, the code generation can change
** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@ -138,12 +138,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */
TValue *stv = s2v(L->top++); /* reserve stack space for string */
TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
L->top--; /* remove string from stack */
L->top.p--; /* remove string from stack */
}
return ts;
}

View File

@ -71,11 +71,24 @@ typedef signed char ls_byte;
/*
** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
** conversion of pointer to unsigned integer: this is for hashing only;
** there is no problem if the integer cannot hold the whole pointer
** value. (In strict ISO C this may cause undefined behavior, but no
** actual machine seems to bother.)
*/
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
#define L_P2I uintptr_t
#else /* no 'intptr'? */
#define L_P2I uintmax_t /* use the largest available integer */
#endif
#else /* C89 option */
#define L_P2I size_t
#endif
#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))

View File

@ -267,7 +267,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */
#if (ULONG_MAX >> 31 >> 31) >= 3
#if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
@ -277,9 +277,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Integer' has at least 64 bits */
/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
#endif
@ -500,12 +500,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) {
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
}
/* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) {
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
}
#endif /* } */

View File

@ -22,25 +22,6 @@
#include "lstate.h"
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail whenever not building initial state.
** (This fail will trigger 'tryagain' and a full GC cycle at every
** allocation.)
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (completestate(g) && ns > 0) /* frees never fail */
return NULL; /* fail */
else /* normal allocation */
return (*g->frealloc)(g->ud, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
#endif
/*
** About the realloc function:
@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/
/*
** Macro to call the allocation function.
*/
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
/*
** When an allocation fails, it will try again after an emergency
** collection, except when it cannot run a collection. The GC should
** not be called while the state is not fully built, as the collector
** is not yet fully initialized. Also, it should not be called when
** 'gcstopem' is true, because then the interpreter is in the middle of
** a collection step.
*/
#define cantryagain(g) (completestate(g) && !g->gcstopem)
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail except when freeing a block (frees never
** fail) and when it cannot try again; this fail will trigger 'tryagain'
** and a full GC cycle at every allocation.
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (ns > 0 && cantryagain(g))
return NULL; /* fail */
else /* normal allocation */
return callfrealloc(g, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
#endif
/*
@ -132,7 +150,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
(*g->frealloc)(g->ud, block, osize, 0);
callfrealloc(g, block, osize, 0);
g->GCdebt -= osize;
}
@ -140,19 +158,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/*
** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again.
** The GC should not be called while state is not fully built, as the
** collector is not yet fully initialized. Also, it should not be called
** when 'gcstopem' is true, because then the interpreter is in the
** middle of a collection step.
*/
static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) {
global_State *g = G(L);
if (completestate(g) && !g->gcstopem) {
if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
return callfrealloc(g, block, osize, nsize); /* try again */
}
else return NULL; /* cannot free any memory without a full state */
else return NULL; /* cannot run an emergency collection */
}

View File

@ -708,8 +708,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] =
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
static const lua_CFunction searchers[] = {
searcher_preload,
searcher_Lua,
searcher_C,
searcher_Croot,
NULL
};
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);

View File

@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2);
case LUA_OPSHR: return luaV_shiftl(v1, -v2);
case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0;
@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** ===================================================================
*/
/* size for buffer space used by 'luaO_pushvfstring' */
#define BUFVFS 200
/*
** Size for buffer space used by 'luaO_pushvfstring'. It should be
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
** so that 'luaG_addinfo' can work directly on the buffer.
*/
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
int pushed; /* number of string pieces already on the stack */
int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
** Push given string to the stack, as part of the buffer, and
** join the partial strings in the stack into one.
** Push given string to the stack, as part of the result, and
** join it to previous partial result if there is one.
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
** This call cannot invoke metamethods, as both operands must be
** strings. It can, however, raise an error if the result is too
** long. In that case, 'luaV_concat' frees the extra slot before
** raising the error.
*/
static void pushstr (BuffFS *buff, const char *str, size_t l) {
static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
L->top++; /* may use one extra slot */
buff->pushed++;
luaV_concat(L, buff->pushed); /* join partial results into one */
buff->pushed = 1;
setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
L->top.p++; /* may use one slot from EXTRA_STACK */
if (!buff->pushed) /* no previous string on the stack? */
buff->pushed = 1; /* now there is one */
else /* join previous string with new one */
luaV_concat(L, 2);
}
@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/*
** Add a number to the buffer.
** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
@ -532,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
return svalue(s2v(L->top - 1));
return svalue(s2v(L->top.p - 1));
}

View File

@ -52,6 +52,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
/* not used, but may avoid warnings for uninitialized value */
lu_byte ub;
} Value;
@ -155,6 +157,17 @@ typedef union StackValue {
/* index to stack elements */
typedef StackValue *StkId;
/*
** When reallocating the stack, change all pointers to the stack into
** proper offsets.
*/
typedef union {
StkId p; /* actual pointer */
ptrdiff_t offset; /* used while the stack is being reallocated */
} StkIdRel;
/* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val)
@ -615,8 +628,10 @@ typedef struct Proto {
*/
typedef struct UpVal {
CommonHeader;
lu_byte tbc; /* true if it represents a to-be-closed variable */
TValue *v; /* points to stack or to its own value */
union {
TValue *p; /* points to stack or to its own value */
ptrdiff_t offset; /* used while the stack is being reallocated */
} v;
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */

View File

@ -21,7 +21,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
isJ sJ(25) | Op(7) |
isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the

View File

@ -30,23 +30,14 @@
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
/* options for ANSI C 89 (only 1-char options) */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
#elif defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
@ -138,21 +129,27 @@
/* }================================================================== */
#if !defined(l_system)
#if defined(LUA_USE_IOS)
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
#else
#define l_system(cmd) system(cmd) /* default definition */
#endif
#endif
static int os_execute (lua_State *L) {
#if !defined(__APPLE__)
const char *cmd = luaL_optstring(L, 1, NULL);
int stat;
errno = 0;
stat = system(cmd);
stat = l_system(cmd);
if (cmd != NULL)
return luaL_execresult(L, stat);
else {
lua_pushboolean(L, stat); /* true if there is a shell */
return 1;
}
#else
return 0;
#endif
}
@ -263,9 +260,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d;
}
else {
/* unsigned avoids overflow when lua_Integer has 32 bits */
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
: (lua_Integer)INT_MIN + delta <= res))
if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}

View File

@ -468,6 +468,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@ -520,12 +521,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/*
** Solves the goto at index 'g' to given 'label' and removes it
** from the list of pending goto's.
** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error.
*/
static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i;
Labellist *gl = &ls->dyd->gt; /* list of goto's */
Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@ -579,7 +580,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/*
** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true
** if any of the goto's need to close upvalues.
** if any of the gotos need to close upvalues.
*/
static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
@ -600,7 +601,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/*
** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its
** block. Solves all pending goto's to this new label and adds
** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary.
** Returns true iff it added a close instruction.
*/
@ -673,19 +674,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls;
int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
if (bl->isloop) /* fix pending breaks? */
removevars(fs, bl->nactvar); /* remove block locals */
lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
if (!hasclose && bl->previous && bl->upval)
if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
fs->bl = bl->previous;
removevars(fs, bl->nactvar);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */
if (bl->previous) /* inner block? */
movegotosout(fs, bl); /* update pending gotos to outer block */
fs->bl = bl->previous; /* current block now is previous one */
if (bl->previous) /* was it a nested block? */
movegotosout(fs, bl); /* update pending gotos to enclosing block */
else {
if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
}
}
@ -1943,10 +1944,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate;
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */
setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue2s(L, L->top, lexstate.h); /* anchor it */
sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@ -1960,7 +1961,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
L->top--; /* remove scanner's table */
L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */
}

View File

@ -180,33 +180,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist = L1->stack;
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
setnilvalue(s2v(L1->stack + i)); /* erase new stack */
L1->top = L1->stack;
L1->stack_last = L1->stack + BASIC_STACK_SIZE;
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
L1->top.p = L1->stack.p;
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = CIST_C;
ci->func = L1->top;
ci->func.p = L1->top.p;
ci->u.c.k = NULL;
ci->nresults = 0;
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
L1->top++;
ci->top = L1->top + LUA_MINSTACK;
setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
L1->top.p++;
ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci;
}
static void freestack (lua_State *L) {
if (L->stack == NULL)
if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@ -248,7 +248,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->stack.p = NULL;
L->ci = NULL;
L->nci = 0;
L->twups = L; /* thread has no upvalues */
@ -284,20 +284,16 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) {
global_State *g;
global_State *g = G(L);
GCObject *o;
lua_State *L1;
lua_lock(L);
g = G(L);
luaC_checkGC(L);
/* create new thread */
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
L1->marked = luaC_white(g);
L1->tt = LUA_VTHREAD;
/* link it on list 'allgc' */
L1->next = g->allgc;
g->allgc = obj2gco(L1);
o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
L1 = gco2th(o);
/* anchor it on L stack */
setthvalue2s(L, L->top, L1);
setthvalue2s(L, L->top.p, L1);
api_incr_top(L);
preinit_thread(L1, g);
L1->hookmask = L->hookmask;
@ -316,7 +312,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
luaF_closeupval(L1, L1->stack); /* close all upvalues */
luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
@ -326,32 +322,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
ci->func = L->stack;
setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
ci->func.p = L->stack.p;
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1);
luaD_seterrorobj(L, status, L->stack.p + 1);
else
L->top = L->stack + 1;
ci->top = L->top + LUA_MINSTACK;
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
L->top.p = L->stack.p + 1;
ci->top.p = L->top.p + LUA_MINSTACK;
luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status;
}
LUA_API int lua_resetthread (lua_State *L) {
LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status;
lua_lock(L);
L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status);
lua_unlock(L);
return status;
}
/*
** Deprecated! Use 'lua_closethread' instead.
*/
LUA_API int lua_resetthread (lua_State *L) {
return lua_closethread(L, NULL);
}
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@ -426,7 +431,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message
*/
void luaE_warnerror (lua_State *L, const char *where) {
TValue *errobj = s2v(L->top - 1); /* error object */
TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
? svalue(errobj)
: "error object is not a string";

View File

@ -9,6 +9,11 @@
#include "lua.h"
/* Some header files included here need this definition */
typedef struct CallInfo CallInfo;
#include "lobject.h"
#include "ltm.h"
#include "lzio.h"
@ -139,7 +144,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */
@ -169,9 +174,9 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/
typedef struct CallInfo {
StkId func; /* function index in the stack */
StkId top; /* top for this function */
struct CallInfo {
StkIdRel func; /* function index in the stack */
StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
@ -196,7 +201,7 @@ typedef struct CallInfo {
} u2;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
} CallInfo;
};
/*
@ -291,7 +296,7 @@ typedef struct global_State {
struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */
@ -306,13 +311,13 @@ struct lua_State {
lu_byte status;
lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */
StkId top; /* first free slot in the stack */
StkIdRel top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
StkId stack_last; /* end of stack (last element + 1) */
StkId stack; /* stack base */
StkIdRel stack_last; /* end of stack (last element + 1) */
StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
StkId tbclist; /* list of to-be-closed variables */
StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */

View File

@ -570,7 +570,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex");
init: /* using goto's to optimize tail recursion */
init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */
switch (*p) {
case '(': { /* start capture */

View File

@ -107,7 +107,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
if (ui <= (unsigned int)INT_MAX)
if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui));
else
return hashmod(t, ui);
@ -257,9 +257,11 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */
#endif
#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@ -488,7 +490,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow");
size = twoto(lsize);
t->node = luaM_newvector(L, size, Node);
for (i = 0; i < (int)size; i++) {
for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
@ -975,6 +977,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif

View File

@ -59,7 +59,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (const Table *t);
#endif

View File

@ -93,7 +93,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {

View File

@ -102,12 +102,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
StkId func = L->top;
StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */
L->top = func + 4;
L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 0);
@ -119,18 +119,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res);
StkId func = L->top;
StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
L->top += 3;
L->top.p += 3;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 1);
else
luaD_callnoyield(L, func, 1);
res = restorestack(L, result);
setobjs2s(L, res, --L->top); /* move result to its place */
setobjs2s(L, res, --L->top.p); /* move result to its place */
}
@ -165,7 +165,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) {
StkId top = L->top;
StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@ -200,15 +200,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
return !l_isfalse(s2v(L->top));
if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
if (callbinTM(L, p2, p1, L->top, TM_LT)) {
if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
return l_isfalse(s2v(L->top));
return l_isfalse(s2v(L->top.p));
}
/* else error will remove this 'ci'; no need to clear mark */
}
@ -238,20 +238,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) {
int i;
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */
setobjs2s(L, L->top++, ci->func);
setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) {
setobjs2s(L, L->top++, ci->func + i);
setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
setobjs2s(L, L->top.p++, ci->func.p + i);
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
}
ci->func += actual + 1;
ci->top += actual + 1;
lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
ci->func.p += actual + 1;
ci->top.p += actual + 1;
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
@ -261,10 +261,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */
L->top = where + nextra; /* next instruction will need top */
L->top.p = where + nextra; /* next instruction will need top */
}
for (i = 0; i < wanted && i < nextra; i++)
setobjs2s(L, where + i, ci->func - nextra + i);
setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}

View File

@ -9,6 +9,7 @@
#include "lobject.h"
#include "lstate.h"
/*
@ -95,8 +96,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
struct CallInfo *ci, const Proto *p);
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
CallInfo *ci, const Proto *p);
LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted);

View File

@ -177,10 +177,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base.
** (If there is no interpreter's name either, 'script' is -1, so
** table sizes are zero.)
*/
static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg;
if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) {
@ -268,14 +269,23 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds
** any invalid argument). 'first' returns the first not-handled argument
** (either the script name or a bad argument in case of error).
** needed before running any Lua code or an error code if it finds any
** invalid argument. In case of error, 'first' is the index of the bad
** argument. Otherwise, 'first' is -1 if there is no program name,
** 0 if there is no script name, or the index of the script name.
*/
static int collectargs (char **argv, int *first) {
int args = 0;
int i;
for (i = 1; argv[i] != NULL; i++) {
if (argv[0] != NULL) { /* is there a program name? */
if (argv[0][0]) /* not empty? */
progname = argv[0]; /* save it */
}
else { /* no program name */
*first = -1;
return 0;
}
for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i;
if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */
@ -316,7 +326,7 @@ static int collectargs (char **argv, int *first) {
return has_error;
}
}
*first = i; /* no script name */
*first = 0; /* no script name */
return args;
}
@ -609,8 +619,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2);
int script;
int args = collectargs(argv, &script);
int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */
if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0;
@ -623,19 +633,21 @@ static int pmain (lua_State *L) {
}
luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
if (!runargs(L, argv, script)) /* execute arguments -e and -l */
if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */
if (script < argc && /* execute main script (if there is one) */
handle_script(L, argv + script) != LUA_OK)
return 0;
if (script > 0) { /* execute main script (if there is one) */
if (handle_script(L, argv + script) != LUA_OK)
return 0; /* interrupt in case of error */
}
if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version();
doREPL(L); /* do read-eval-print loop */
@ -654,6 +666,7 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */

View File

@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "4"
#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
/*
** Type used by the debug API to collect debug information
*/
typedef struct lua_Debug lua_Debug;
/*
** Functions to be called by the debugger in specific events
*/
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/*
@ -153,7 +163,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API int (lua_resetthread) (lua_State *L);
LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@ -442,12 +453,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@ -492,7 +497,7 @@ struct lua_Debug {
/******************************************************************************
* Copyright (C) 1994-2022 Lua.org, PUC-Rio.
* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

View File

@ -121,7 +121,7 @@ static int doargs(int argc, char* argv[])
return i;
}
#define FUNCTION "(function()end)();"
#define FUNCTION "(function()end)();\n"
static const char* reader(lua_State* L, void* ud, size_t* size)
{
@ -138,7 +138,7 @@ static const char* reader(lua_State* L, void* ud, size_t* size)
}
}
#define toproto(L,i) getproto(s2v(L->top+(i)))
#define toproto(L,i) getproto(s2v(L->top.p+(i)))
static const Proto* combine(lua_State* L, int n)
{
@ -155,8 +155,6 @@ static const Proto* combine(lua_State* L, int n)
f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
}
luaM_freearray(L,f->lineinfo,f->sizelineinfo);
f->sizelineinfo=0;
return f;
}
}

View File

@ -70,6 +70,12 @@
#endif
#if defined(LUA_USE_IOS)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN
#endif
/*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/
@ -728,7 +734,7 @@
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
** (It must fit into max(size_t)/32.)
** (It must fit into max(size_t)/32 and max(int)/2.)
*/
#if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000
@ -747,14 +753,15 @@
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information.
** of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
** buffer system.
*/
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))

View File

@ -120,10 +120,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
}
else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */
L->top--; /* pop string */
L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
return ts;
@ -248,6 +248,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S);
}
n = loadInt(S);
if (n != 0) /* does it have debug information? */
n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f);
}
@ -321,7 +323,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z;
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
setclLvalue2s(L, L->top, cl);
setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);

View File

@ -25,6 +25,9 @@
#define MAXUTF 0x7FFFFFFFu
#define MSGInvalid "invalid UTF-8 code"
/*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/
@ -35,7 +38,8 @@ typedef unsigned long utfint;
#endif
#define iscont(p) ((*(p) & 0xC0) == 0x80)
#define iscont(c) (((c) & 0xC0) == 0x80)
#define iscontp(p) iscont(*(p))
/* from strlib */
@ -65,7 +69,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
@ -140,7 +144,7 @@ static int codepoint (lua_State *L) {
utfint code;
s = utf8_decode(s, &code, !lax);
if (s == NULL)
return luaL_error(L, "invalid UTF-8 code");
return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code);
n++;
}
@ -190,16 +194,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds");
if (n == 0) {
/* find beginning of current byte sequence */
while (posi > 0 && iscont(s + posi)) posi--;
while (posi > 0 && iscontp(s + posi)) posi--;
}
else {
if (iscont(s + posi))
if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */
posi--;
} while (posi > 0 && iscont(s + posi));
} while (posi > 0 && iscontp(s + posi));
n++;
}
}
@ -208,7 +212,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */
posi++;
} while (iscont(s + posi)); /* (cannot pass final '\0') */
} while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--;
}
}
@ -226,15 +230,15 @@ static int iter_aux (lua_State *L, int strict) {
const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) {
while (iscont(s + n)) n++; /* skip continuation bytes */
while (iscontp(s + n)) n++; /* go to next character */
}
if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
const char *next = utf8_decode(s + n, &code, strict);
if (next == NULL)
return luaL_error(L, "invalid UTF-8 code");
if (next == NULL || iscontp(next))
return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1);
lua_pushinteger(L, code);
return 2;
@ -253,7 +257,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2);
luaL_checkstring(L, 1);
const char *s = luaL_checkstring(L, 1);
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);

View File

@ -608,8 +608,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
return !l_isfalse(s2v(L->top));
luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
return !l_isfalse(s2v(L->top.p));
}
}
@ -633,17 +633,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/*
** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'.
** from 'L->top.p - total' up to 'L->top.p - 1'.
*/
void luaV_concat (lua_State *L, int total) {
if (total == 1)
return; /* "all" values already concatenated */
do {
StkId top = L->top;
StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1)))
luaT_tryconcatTM(L);
luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@ -656,8 +656,10 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1));
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow");
}
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@ -671,8 +673,8 @@ void luaV_concat (lua_State *L, int total) {
}
setsvalue2s(L, top - n, ts); /* create result */
}
total -= n-1; /* got 'n' strings to create 1 new */
L->top -= n-1; /* popped 'n' strings and pushed one */
total -= n - 1; /* got 'n' strings to create one new */
L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */
}
@ -763,12 +765,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
/*
** Shift left operation. (Shift right just negates 'y'.)
*/
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0;
@ -808,26 +808,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/
void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci;
StkId base = ci->func + 1;
StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break;
}
case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top);
setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break;
}
case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
int res = !l_isfalse(s2v(L->top - 1));
L->top--;
int res = !l_isfalse(s2v(L->top.p - 1));
L->top.p--;
#if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */
@ -840,11 +840,11 @@ void luaV_finishOp (lua_State *L) {
break;
}
case OP_CONCAT: {
StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */
StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
int a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */
L->top = top - 1; /* top is one after last element (at top-2) */
L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
break;
}
@ -856,7 +856,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */
L->top = ra + ci->u2.nres;
L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--;
break;
@ -898,6 +898,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation.
*/
#define op_arithI(L,iop,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
@ -926,6 +927,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands.
*/
#define op_arithf(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
@ -935,6 +937,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats.
*/
#define op_arithfK(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); }
@ -944,6 +947,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats.
*/
#define op_arith_aux(L,v1,v2,iop,fop) { \
StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@ -973,6 +977,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand.
*/
#define op_bitwiseK(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
@ -986,6 +991,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands.
*/
#define op_bitwise(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
@ -1000,18 +1006,19 @@ void luaV_finishOp (lua_State *L) {
** integers.
*/
#define op_order(L,opi,opn,other) { \
int cond; \
TValue *rb = vRB(i); \
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
lua_Integer ia = ivalue(s2v(ra)); \
lua_Integer ib = ivalue(rb); \
cond = opi(ia, ib); \
} \
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
cond = opn(s2v(ra), rb); \
else \
Protect(cond = other(L, s2v(ra), rb)); \
docondjump(); }
StkId ra = RA(i); \
int cond; \
TValue *rb = vRB(i); \
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
lua_Integer ia = ivalue(s2v(ra)); \
lua_Integer ib = ivalue(rb); \
cond = opi(ia, ib); \
} \
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
cond = opn(s2v(ra), rb); \
else \
Protect(cond = other(L, s2v(ra), rb)); \
docondjump(); }
/*
@ -1019,20 +1026,21 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.)
*/
#define op_orderI(L,opi,opf,inv,tm) { \
int cond; \
int im = GETARG_sB(i); \
if (ttisinteger(s2v(ra))) \
cond = opi(ivalue(s2v(ra)), im); \
else if (ttisfloat(s2v(ra))) { \
lua_Number fa = fltvalue(s2v(ra)); \
lua_Number fim = cast_num(im); \
cond = opf(fa, fim); \
} \
else { \
int isf = GETARG_C(i); \
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
} \
docondjump(); }
StkId ra = RA(i); \
int cond; \
int im = GETARG_sB(i); \
if (ttisinteger(s2v(ra))) \
cond = opi(ivalue(s2v(ra)), im); \
else if (ttisfloat(s2v(ra))) { \
lua_Number fa = fltvalue(s2v(ra)); \
lua_Number fim = cast_num(im); \
cond = opf(fa, fim); \
} \
else { \
int isf = GETARG_C(i); \
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
} \
docondjump(); }
/* }================================================================== */
@ -1061,7 +1069,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap)
#define updatebase(ci) (base = ci->func + 1)
#define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \
@ -1096,7 +1104,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors.
*/
#define savestate(L,ci) (savepc(L), L->top = ci->top)
#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/*
@ -1116,7 +1124,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \
{ luaC_condGC(L, (savepc(L), L->top = (c)), \
{ luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \
luai_threadyield(L); }
@ -1128,7 +1136,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \
} \
i = *(pc++); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
}
#define vmdispatch(o) switch(o)
@ -1148,7 +1155,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
startfunc:
trap = L->hookmask;
returning: /* trap already set */
cl = clLvalue(s2v(ci->func));
cl = clLvalue(s2v(ci->func.p));
k = cl->p->k;
pc = ci->u.l.savedpc;
if (l_unlikely(trap)) {
@ -1160,60 +1167,68 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
base = ci->func + 1;
base = ci->func.p + 1;
/* main loop of interpreter */
for (;;) {
Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */
vmfetch();
#if 0
/* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif
lua_assert(base == ci->func + 1);
lua_assert(base <= L->top && L->top < L->stack_last);
lua_assert(base == ci->func.p + 1);
lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */
lua_assert(isIT(i) || (cast_void(L->top = base), 1));
lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
StkId ra = RA(i);
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADI) {
StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmbreak;
}
vmcase(OP_LOADF) {
StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmbreak;
}
vmcase(OP_LOADK) {
StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADKX) {
StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADFALSE) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LFALSESKIP) {
StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++; /* skip next instruction */
vmbreak;
}
vmcase(OP_LOADTRUE) {
StkId ra = RA(i);
setbtvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LOADNIL) {
StkId ra = RA(i);
int b = GETARG_B(i);
do {
setnilvalue(s2v(ra++));
@ -1221,19 +1236,22 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETUPVAL) {
StkId ra = RA(i);
int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v);
setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak;
}
vmcase(OP_SETUPVAL) {
StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, s2v(ra));
setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
StkId ra = RA(i);
const TValue *slot;
TValue *upval = cl->upvals[GETARG_B(i)]->v;
TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
@ -1244,6 +1262,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETTABLE) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = vRC(i);
@ -1258,6 +1277,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETI) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
@ -1272,6 +1292,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_GETFIELD) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
@ -1285,7 +1306,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
vmcase(OP_SETTABUP) {
const TValue *slot;
TValue *upval = cl->upvals[GETARG_A(i)]->v;
TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */
@ -1297,6 +1318,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETTABLE) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */
@ -1311,6 +1333,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETI) {
StkId ra = RA(i);
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
@ -1325,6 +1348,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SETFIELD) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
@ -1337,6 +1361,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
Table *t;
@ -1346,7 +1371,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */
L->top = ra + 1; /* correct top in case of emergency GC */
L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
@ -1355,6 +1380,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SELF) {
StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
@ -1384,6 +1410,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MODK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
@ -1396,6 +1423,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIVK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@ -1412,6 +1440,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SHRI) {
StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@ -1421,6 +1450,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_SHLI) {
StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@ -1442,6 +1472,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MOD) {
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
@ -1454,6 +1485,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIV) { /* floor division */
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@ -1478,6 +1510,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBIN) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i);
@ -1487,6 +1520,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBINI) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i);
@ -1496,6 +1530,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MMBINK) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i);
@ -1505,6 +1540,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_UNM) {
StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Number nb;
if (ttisinteger(rb)) {
@ -1519,6 +1555,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_BNOT) {
StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
@ -1529,6 +1566,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_NOT) {
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
@ -1537,21 +1575,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_LEN) {
StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak;
}
vmcase(OP_CONCAT) {
StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */
L->top = ra + n; /* mark the end of concat operands */
L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n));
checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak;
}
vmcase(OP_CLOSE) {
StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
StkId ra = RA(i);
/* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra));
vmbreak;
@ -1561,6 +1603,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQ) {
StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@ -1576,6 +1619,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQK) {
StkId ra = RA(i);
TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb);
@ -1583,6 +1627,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_EQI) {
StkId ra = RA(i);
int cond;
int im = GETARG_sB(i);
if (ttisinteger(s2v(ra)))
@ -1611,11 +1656,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_TEST) {
StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i))
pc++;
@ -1626,11 +1673,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_CALL) {
StkId ra = RA(i);
CallInfo *newci;
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */
L->top = ra + b; /* top signals number of arguments */
L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */
savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@ -1642,54 +1690,57 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_TAILCALL) {
StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0)
L->top = ra + b;
L->top.p = ra + b;
else /* previous instruction set top */
b = cast_int(L->top - ra);
b = cast_int(L->top.p - ra);
savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */
lua_assert(L->tbclist < base); /* no pending tbc variables */
lua_assert(base == ci->func + 1);
lua_assert(L->tbclist.p < base); /* no pending tbc variables */
lua_assert(base == ci->func.p + 1);
}
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */
else { /* C function? */
ci->func -= delta; /* restore 'func' (if vararg) */
ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */
}
}
vmcase(OP_RETURN) {
StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */
n = cast_int(L->top - ra); /* get what is available */
n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */
if (L->top < ci->top)
L->top = ci->top;
if (L->top.p < ci->top.p)
L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci);
updatestack(ci);
}
if (nparams1) /* vararg function? */
ci->func -= ci->u.l.nextraargs + nparams1;
L->top = ra + n; /* set call for 'luaD_poscall' */
ci->func.p -= ci->u.l.nextraargs + nparams1;
L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret;
}
vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) {
L->top = ra;
StkId ra = RA(i);
L->top.p = ra;
savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1;
@ -1697,15 +1748,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
else { /* do the 'poscall' here */
int nres;
L->ci = ci->previous; /* back to caller */
L->top = base - 1;
L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
setnilvalue(s2v(L->top++)); /* all results are nil */
setnilvalue(s2v(L->top.p++)); /* all results are nil */
}
goto ret;
}
vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) {
L->top = ra + 1;
StkId ra = RA(i);
L->top.p = ra + 1;
savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1;
@ -1714,12 +1766,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */
if (nres == 0)
L->top = base - 1; /* asked for no results */
L->top.p = base - 1; /* asked for no results */
else {
StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */
L->top = base;
L->top.p = base;
for (; l_unlikely(nres > 1); nres--)
setnilvalue(s2v(L->top++)); /* complete missing results */
setnilvalue(s2v(L->top.p++)); /* complete missing results */
}
}
ret: /* return from a Lua function */
@ -1731,6 +1784,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
}
vmcase(OP_FORLOOP) {
StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */
@ -1749,12 +1803,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_FORPREP) {
StkId ra = RA(i);
savestate(L, ci); /* in case of errors */
if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak;
}
vmcase(OP_TFORPREP) {
StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i);
@ -1763,7 +1819,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
l_tforcall:
l_tforcall: {
StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after
@ -1771,29 +1828,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
*/
/* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra));
L->top = ra + 4 + 3;
L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
}
}}
vmcase(OP_TFORLOOP) {
l_tforloop:
l_tforloop: {
StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */
}
vmbreak;
}
}}
vmcase(OP_SETLIST) {
StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
n = cast_int(L->top - ra) - 1; /* get up to the top */
n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else
L->top = ci->top; /* correct top in case of emergency GC */
L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@ -1810,12 +1869,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_CLOSURE) {
StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak;

View File

@ -110,6 +110,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); }
/*
** Shift right is the same as shift left with a negative 'y'
*/
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);