├── .gitignore ├── CONTRIBUTING.md ├── INSTALL.md ├── LICENSE ├── PATENTS ├── README.md ├── fblualib ├── CMakeLists.txt ├── CrossThreadRegistry.h ├── Future.cpp ├── Future.h ├── LuaUtils-inl.h ├── LuaUtils.cpp ├── LuaUtils.h ├── README.md ├── Reactor.cpp ├── Reactor.h ├── UserData.cpp ├── UserData.h ├── atomicvector │ ├── AtomicVector.cpp │ ├── AtomicVector.h │ ├── AtomicVectorTest.cpp │ ├── fb │ │ └── atomicvector │ │ │ ├── _config.lua.in │ │ │ └── init.lua │ ├── rockspec │ │ └── atomicvector-0.1-1.rockspec │ └── test │ │ └── atomicvector_test.lua ├── build.sh ├── cmake │ ├── FindFBLuaLib.cmake │ ├── FindFolly.cmake │ ├── FindGlog.cmake │ ├── FindMatIO.cmake │ ├── FindNumPy.cmake │ ├── FindTHPP.cmake │ ├── FindThrift.cmake │ └── MultiLevelIncludes.cmake ├── complex │ ├── fb │ │ └── complex │ │ │ └── init.lua │ └── rockspec │ │ └── fbcomplex-0.1-1.rockspec ├── debugger │ ├── README.md │ ├── fb │ │ └── debugger │ │ │ ├── breakpoint.lua │ │ │ ├── init.lua │ │ │ ├── types.lua │ │ │ └── utils.lua │ └── rockspec │ │ └── fbdebugger-0.1-1.rockspec ├── editline │ ├── CMakeLists.txt │ ├── README.md │ ├── editline_test.lua │ ├── fb │ │ └── editline │ │ │ ├── _config.lua.in │ │ │ ├── completer.lua │ │ │ └── init.lua │ └── rockspec │ │ └── fbeditline-0.1-1.rockspec ├── ffivector │ ├── CMakeLists.txt │ ├── FFIVector.cpp │ ├── README.md │ ├── fb │ │ └── ffivector │ │ │ ├── _config.lua.in │ │ │ └── init.lua │ ├── rockspec │ │ └── fbffivector-0.1-1.rockspec │ └── test │ │ └── ffivector_test.lua ├── luaunit │ ├── README.md │ ├── fb │ │ └── luaunit │ │ │ └── init.lua │ └── rockspec │ │ └── fbluaunit-0.1-1.rockspec ├── mattorch │ ├── CMakeLists.txt │ ├── MatTorch.cpp │ ├── README.md │ ├── fb │ │ └── mattorch │ │ │ └── init.lua │ └── rockspec │ │ └── fbmattorch-0.1-1.rockspec ├── python │ ├── CMakeLists.txt │ ├── Debug.cpp │ ├── Debug.h │ ├── Lib.cpp │ ├── LuaToPython.cpp │ ├── LuaToPython.h │ ├── NumpyArrayAllocator.cpp │ ├── NumpyArrayAllocator.h │ ├── PythonToLua.cpp │ ├── PythonToLua.h │ ├── README.md │ ├── Ref.cpp │ ├── Ref.h │ ├── Storage-inl.h │ ├── Storage.cpp │ ├── Storage.h │ ├── Utils-inl.h │ ├── Utils.cpp │ ├── Utils.h │ ├── cmake │ │ ├── FindGlog.cmake │ │ ├── FindNumPy.cmake │ │ ├── FindTHPP.cmake │ │ └── MultiLevelIncludes.cmake │ ├── fb │ │ └── python │ │ │ └── init.lua │ ├── rockspec │ │ └── fbpython-0.1-1.rockspec │ └── test │ │ └── lua_python_test.lua ├── test │ ├── LuaUtilsTest.cpp │ ├── PromiseTest.cpp │ └── UserDataTest.cpp ├── thrift │ ├── CMakeLists.txt │ ├── ChunkedCompression.cpp │ ├── ChunkedCompression.h │ ├── Encoding.cpp │ ├── Encoding.h │ ├── LuaObject-inl.h │ ├── LuaObject.cpp │ ├── LuaObject.h │ ├── LuaSerialization.cpp │ ├── README.md │ ├── Serialization.cpp │ ├── Serialization.h │ ├── fb │ │ └── thrift │ │ │ └── init.lua │ ├── if │ │ ├── ChunkedCompression.thrift │ │ └── LuaObject.thrift │ ├── rockspec │ │ └── fbthrift-0.1-1.rockspec │ └── test │ │ ├── LuaObjectTestModule.cpp │ │ ├── SerializerTest.cpp │ │ ├── lua_object_test.lua │ │ └── thrift_test.lua ├── torch │ ├── AsyncRNG.cpp │ ├── CMakeLists.txt │ ├── README.md │ └── rockspec │ │ └── fbtorch-0.1-1.rockspec ├── trepl │ ├── README.md │ ├── fb │ │ └── trepl │ │ │ ├── base.lua │ │ │ └── init.lua │ └── rockspec │ │ └── fbtrepl-0.1-1.rockspec └── util │ ├── CMakeLists.txt │ ├── README.md │ ├── Reactor.cpp │ ├── Util.cpp │ ├── fb │ └── util │ │ ├── _config.lua.in │ │ ├── _promise_registry.lua │ │ ├── data.lua │ │ ├── dbg.lua │ │ ├── digraph.lua │ │ ├── error.lua │ │ ├── file.lua │ │ ├── future.lua │ │ ├── init.lua │ │ ├── logging.lua │ │ ├── multi_level.lua │ │ ├── reactor.lua │ │ ├── stats.lua │ │ ├── timing.lua │ │ └── trace.lua │ ├── rockspec │ └── fbutil-0.1-1.rockspec │ └── test │ ├── digraph_test.lua │ ├── error_handling_test.lua │ ├── file_test.lua │ ├── find_test.lua │ ├── future_test.lua │ ├── imports │ ├── a.lua │ ├── b │ │ ├── c.lua │ │ └── init.lua │ ├── d.lua │ └── init.lua │ ├── reactor_test.lua │ ├── stats_test.lua │ ├── trace_test.lua │ └── util_test.lua └── install_all.sh /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | gtest-* 3 | 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to FBLUA 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Our Development Process 6 | This project is developed internally at Facebook inside a private repository. 7 | Changes are periodically pushed to the open-source branch. Pull requests are 8 | integrated manually into our private repository first, and they then get 9 | propagated to the public repository with the next push. 10 | 11 | ## Pull Requests 12 | We actively welcome your pull requests. 13 | 1. Fork the repo and create your branch from `master`. 14 | 2. If you've added code that should be tested, add tests 15 | 3. If you've changed APIs, update the documentation. 16 | 4. Ensure the test suite passes. 17 | 5. Make sure your code lints. 18 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 19 | 20 | ## Contributor License Agreement ("CLA") 21 | In order to accept your pull request, we need you to submit a CLA. You only need 22 | to do this once to work on any of Facebook's open source projects. 23 | 24 | Complete your CLA here: 25 | 26 | ## Issues 27 | We use GitHub issues to track public bugs. Please ensure your description is 28 | clear and has sufficient instructions to be able to reproduce the issue. 29 | 30 | ## Coding Style 31 | 32 | ### C++ 33 | * 2 spaces for indentation rather than tabs 34 | * 80 character line length 35 | * Name classes LikeThis, functions and methods likeThis, data members 36 | likeThis_. 37 | * Most naming and formatting recommendations from 38 | [Google's C++ Coding Style Guide]( 39 | http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) apply (but 40 | not the restrictions; exceptions and templates are fine.) 41 | * Feel free to use [boost](http://www.boost.org/), 42 | [folly](https://github.com/facebook/folly) and 43 | [fbthrift](https://github.com/facebook/fbthrift) 44 | 45 | ### Lua 46 | * Inspired by [PEP 8](http://legacy.python.org/dev/peps/pep-0008/) 47 | * 4 spaces for indentation rather than tabs 48 | * 80 character line length 49 | * Name classes LikeThis, functions, methods, and variables like_this, private 50 | methods _like_this 51 | * Use [Penlight](http://stevedonovan.github.io/Penlight/api/index.html); 52 | specifically pl.class for OOP 53 | * Do not use global variables (except with a very good reason) 54 | * Use [new-style modules](http://lua-users.org/wiki/ModulesTutorial); do not 55 | use the module() function 56 | * Assume [LuaJIT 2.0+](http://luajit.org/), so Lua 5.1 code with LuaJIT's 57 | supported [extensions](http://luajit.org/extensions.html); 58 | [FFI](http://luajit.org/ext_ffi.html) is okay. 59 | 60 | ## License 61 | By contributing to FBLUA, you agree that your contributions will be licensed 62 | under its BSD license. 63 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # FBLuaLib: installation 2 | 3 | ## One-step installation instructions 4 | 5 | If you're on Ubuntu 13.10 or Ubuntu 14.04 (or higher), you can use the 6 | one-stop installation script: 7 | 8 | ``` 9 | curl -sk https://raw.githubusercontent.com/facebook/fblualib/master/install_all.sh | bash 10 | ``` 11 | 12 | This will install [folly](https://github.com/facebook/folly), 13 | [fbthrift](https://github.com/facebook/fbthrift), [Torch](https://torch.ch), 14 | [TH++](https://github.com/facebook/thpp), and FBLuaLib. 15 | 16 | **NOTE** You might need to reinstall Torch even if you already have it installed, as older 17 | versions do not install LuaJIT with Lua 5.2 compatibility. To check, run 18 | `luajit -e ';;'` -- if you get an error ("unexpected symbol near ';'"), 19 | then you need to reinstall. 20 | 21 | ## Detailed installation instructions 22 | 23 | FBLuaLib is composed of a few separate (but interdependent) packages. 24 | 25 | 1. Install [TH++](https://github.com/facebook/thpp) by following 26 | [the instructions](https://github.com/facebook/thpp/blob/master/INSTALL.md) 27 | 2. Install a few additional packages; on Ubuntu 13.10 and 14.04, they are as 28 | follows (feel free to cut and paste the apt-get command below): 29 | ``` 30 | sudo apt-get install \ 31 | libedit-dev \ 32 | libmatio-dev \ 33 | libpython-dev \ 34 | python-numpy 35 | ``` 36 | 2. Build and install FBLuaLib; `cd fblualib; ./build.sh` or follow the steps 37 | in the script yourself. 38 | 4. Try it out! run the default Torch shell (`th`) or, to use 39 | [fb.repl](fblualib/trepl/README.md), `luajit -e "require('fb.trepl').repl()"` 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For FBLUA software 4 | 5 | Copyright (c) 2014, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the fblualib software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook’s rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fblualib: A collection of Lua / Torch utilities 2 | 3 | FBLuaLib is a collection of Lua / Torch utilities developed at Facebook that 4 | we've found useful. Some of these utilities are useful without Torch. 5 | 6 | [LuaJIT](http://luajit.org/) is required, and we currently only support 7 | x86_64 Linux. 8 | 9 | * [C++ LuaUtils](fblualib/README.md) is a collection of C++ utilities useful 10 | for writing Lua extensions 11 | * [fb.util](fblualib/util/README.md) is a collection of low-level Lua utilities 12 | that, in addition to being useful on their own, are depended upon by 13 | everything else. Does not require Torch. 14 | * [fb.editline](fblualib/editline/README.md) is a command line editing library 15 | based on [libedit](http://thrysoee.dk/editline/). Does not require Torch. 16 | * [fb.trepl](fblualib/trepl/README.md) is a configurable Read-Eval-Print loop 17 | with line editing and autocompletion. Does not require Torch (but has 18 | Torch-specific features if Torch is installed) 19 | * [fb.debugger](fblualib/debugger/README.md) is a full-featured source-level 20 | Lua debugger. Does not require Torch. 21 | * [fb.ffivector](fblualib/ffivector/README.md) is a vector of POD types or 22 | strings that does not count toward the Lua heap limit. Does not require 23 | Torch. 24 | * [fb.python](fblualib/python/README.md) is a bridge between Lua and Python, 25 | allowing seamless integration between the two (enabling, for example, 26 | using [SciPy](http://www.scipy.org/) with Lua tensors almost as efficiently 27 | as with native `numpy` arrays; data between Lua tensors and the corresponding 28 | Python counterpart `numpy.ndarray` objects is shared, not copied). Requires 29 | Torch. 30 | * [fb.thrift](fblualib/thrift/README.md) is a library for fast serialization 31 | of arbitrary Lua objects using [Thrift](https://github.com/facebook/fbthrift). 32 | Requires Torch. 33 | * [fb.mattorch](fblualib/mattorch/README.md) is a library for reading 34 | and writing [Matlab](http://www.mathworks.com/products/matlab/) `.mat` files 35 | from Torch without having Matlab installed. 36 | -------------------------------------------------------------------------------- /fblualib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | # Torch messes this up 12 | SET(SAVED_CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) 13 | 14 | # Use our own cmake scripts 15 | SET(CMAKE_MODULE_PATH 16 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake" 17 | "${CMAKE_MODULE_PATH}") 18 | 19 | INCLUDE(MultiLevelIncludes) 20 | MLI_SET_DEPTH(1) 21 | 22 | FIND_PACKAGE(Folly REQUIRED) 23 | FIND_PACKAGE(Glog REQUIRED) 24 | FIND_PACKAGE(Torch REQUIRED) 25 | FIND_PACKAGE(THPP REQUIRED) 26 | 27 | INCLUDE_DIRECTORIES( 28 | ${FOLLY_INCLUDE_DIR} 29 | ${GLOG_INCLUDE_DIR} 30 | ${THPP_INCLUDE_DIR} 31 | ) 32 | 33 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14") 34 | 35 | SET(src 36 | LuaUtils.cpp 37 | Future.cpp 38 | Reactor.cpp 39 | UserData.cpp 40 | ) 41 | 42 | SET(h 43 | LuaUtils.h 44 | LuaUtils-inl.h 45 | Future.h 46 | Reactor.h 47 | UserData.h 48 | CrossThreadRegistry.h 49 | ) 50 | 51 | SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-as-needed") 52 | ADD_LIBRARY(fblualib SHARED ${src}) 53 | 54 | FIND_LIBRARY(lib_luaT luaT 55 | HINTS ${Torch_INSTALL_LIB}) 56 | IF(NOT lib_luaT) 57 | MESSAGE(FATAL_ERROR "libluaT not found") 58 | ENDIF() 59 | TARGET_LINK_LIBRARIES(fblualib 60 | ${lib_luaT} ${THPP_LIBRARIES} ${FOLLY_LIBRARIES} ${GLOG_LIBRARIES}) 61 | 62 | INSTALL(TARGETS fblualib 63 | LIBRARY DESTINATION ${Torch_INSTALL_LIB}) 64 | 65 | INSTALL(FILES ${h} 66 | DESTINATION "${Torch_INSTALL_INCLUDE}/${MLI_INCLUDE_RELATIVE_OUTPUT_DIR}") 67 | -------------------------------------------------------------------------------- /fblualib/CrossThreadRegistry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | namespace { 21 | 22 | template 23 | class CrossThreadRegistry { 24 | std::mutex m_mutex; 25 | typedef std::unordered_map> Registry; 26 | Registry m_registry; 27 | 28 | public: 29 | template 30 | Val* getOrCreate(const Key& key, Lambda factory) { 31 | std::lock_guard l(m_mutex); 32 | auto pos = m_registry.find(key); 33 | if (pos == m_registry.end()) { 34 | pos = m_registry.emplace(key, factory()).first; 35 | } 36 | return pos->second.get(); 37 | } 38 | 39 | template 40 | bool create(const Key& key, Lambda factory) { 41 | std::lock_guard l(m_mutex); 42 | if (folly::get_ptr(m_registry, key)) { 43 | return false; 44 | } 45 | m_registry[key] = factory(); 46 | return true; 47 | } 48 | 49 | bool erase(const Key& key) { 50 | std::lock_guard l(m_mutex); 51 | return m_registry.erase(key); 52 | } 53 | 54 | Val* get(const Key& key) { 55 | std::lock_guard l(m_mutex); 56 | if (auto valp = folly::get_ptr(m_registry, key)) { 57 | return valp->get(); 58 | } 59 | return nullptr; 60 | } 61 | }; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /fblualib/Future.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #include 12 | 13 | namespace fblualib { 14 | 15 | namespace { 16 | 17 | char kPromiseRegistryKey; 18 | 19 | } // namespace 20 | 21 | Promise::Promise(uint64_t key) : key_(key) { 22 | DCHECK_NE(key, 0); 23 | } 24 | 25 | Promise Promise::create(lua_State* L, int numAnchored) { 26 | lua_pushlightuserdata(L, &kPromiseRegistryKey); 27 | lua_gettable(L, LUA_REGISTRYINDEX); 28 | lua_getfield(L, -1, "create"); 29 | // up1 up2... upN mod create_func 30 | lua_insert(L, -2 - numAnchored); 31 | // create_func up1 up2 ... upN mod 32 | lua_pop(L, 1); 33 | // create_func up1 up2 ... upN 34 | lua_call(L, numAnchored, 2); 35 | 36 | // future key 37 | Promise promise(luaGetChecked(L, -1)); 38 | lua_pop(L, 1); 39 | 40 | // future, left on the stack 41 | 42 | return promise; 43 | } 44 | 45 | Promise::Promise(Promise&& other) noexcept 46 | : key_(other.key_) { 47 | other.key_ = 0; 48 | } 49 | 50 | Promise& Promise::operator=(Promise&& other) { 51 | if (this != &other) { 52 | CHECK_EQ(key_, 0) << "Promise overwritten without being fulfilled"; 53 | key_ = other.key_; 54 | other.key_ = 0; 55 | } 56 | return *this; 57 | } 58 | 59 | Promise::~Promise() { 60 | CHECK_EQ(key_, 0) << "Promise destroyed without being fulfilled"; 61 | } 62 | 63 | void Promise::validate(lua_State* /*L*/) { 64 | if (key_ == 0) { 65 | throw std::logic_error("Promise is empty (already fulfilled)"); 66 | } 67 | } 68 | 69 | void Promise::setValue(lua_State* L, int n) { 70 | callPromiseMethod(L, "set_value", n); 71 | } 72 | 73 | void Promise::setError(lua_State* L) { 74 | callPromiseMethod(L, "set_error", 1); 75 | } 76 | 77 | void Promise::callPromiseMethod(lua_State* L, const char* method, int n) { 78 | validate(L); 79 | lua_pushlightuserdata(L, &kPromiseRegistryKey); 80 | lua_gettable(L, LUA_REGISTRYINDEX); 81 | lua_getfield(L, -1, method); 82 | // arg1 arg2 ... argn mod method 83 | lua_insert(L, -2 - n); 84 | lua_pop(L, 1); 85 | // method arg1 arg2 ... argn 86 | luaPush(L, key_); 87 | // method arg1 arg2 ... argn key 88 | lua_insert(L, -1 - n); 89 | // method key arg1 arg2 ... argn 90 | lua_call(L, n + 1, 0); 91 | key_ = 0; 92 | } 93 | 94 | void initFuture(lua_State* L) { 95 | lua_pushlightuserdata(L, &kPromiseRegistryKey); 96 | 97 | lua_getglobal(L, "require"); 98 | lua_pushstring(L, "fb.util._promise_registry"); 99 | lua_call(L, 1, 1); 100 | 101 | lua_settable(L, LUA_REGISTRYINDEX); 102 | } 103 | 104 | } // namespaces 105 | -------------------------------------------------------------------------------- /fblualib/Future.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUALIB_FUTURE_H_ 12 | #define FBLUALIB_FUTURE_H_ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace fblualib { 21 | 22 | /** 23 | * C++ interface to the producer (Promise) side of fb.util.future. 24 | * 25 | * This allows C++ code to create promises and fulfill them later. 26 | * 27 | * This integrates with fb.util.reactor. If you get the reactor's executor 28 | * (by calling its get_executor() method) and schedule promise fulfillment 29 | * in that executor, then Lua code can wait for the corresponding futures 30 | * to complete using the reactor's await() method. 31 | * 32 | * DO NOT CAPTURE THE lua_State* IN THE FUNCTIONS THAT YOU SCHEDULE IN THE 33 | * REACTOR'S EXECUTOR. Use loopingState().L instead. See 34 | * for more details. 35 | */ 36 | class Promise { 37 | public: 38 | Promise() : key_(0) { } 39 | 40 | /** 41 | * Create a promise, leave the associated future on the stack, and 42 | * return a key that you may use to refer to the promise in setPromiseValue / 43 | * setPromiseError later. 44 | * 45 | * Note that the promise is anchored (and won't be garbage collected) until 46 | * you call setPromiseValue / setPromiseError. If numAnchored > 0, then 47 | * numAnchored elements are popped from the stack and anchored as well. 48 | * Anchoring is most useful for userdata objects where you have a (C) 49 | * pointer to the object, but they might be GCed by the time of completion. 50 | * 51 | * The promise is associated with a lua_State until fulfilled. You may only 52 | * call Promise methods when running in the context of that lua_State! 53 | * Promise methods take a lua_State* as the first argument, and will crash 54 | * if that doesn't match the lua_State that the Promise is associated with. 55 | */ 56 | static Promise create(lua_State* L, int numAnchored = 0); 57 | ~Promise(); 58 | 59 | Promise(Promise&& other) noexcept; 60 | Promise& operator=(Promise&& other); /* noexcept override */ 61 | 62 | Promise(const Promise&) = delete; 63 | Promise& operator=(const Promise&) = delete; 64 | 65 | /** 66 | * Fulfill the promise by setting the value to the top n elements of 67 | * the stack (multiple return values); the n elements are popped. 68 | */ 69 | void setValue(lua_State* L, int n = 1); 70 | 71 | /** 72 | * Fulfill the promise by setting the error to the top element of the stack. 73 | * (which is popped). 74 | */ 75 | void setError(lua_State* L); 76 | 77 | /** 78 | * Fulfill the promise by setting the error to a string. 79 | */ 80 | void setErrorFrom(lua_State* L, folly::StringPiece sp) { 81 | luaPush(L, sp); 82 | setError(L); 83 | } 84 | 85 | /** 86 | * Fulfill the promise by setting the error to an appropriate message 87 | * for the given C++ exception. 88 | */ 89 | void setErrorFrom(lua_State* L, const std::exception& exc) { 90 | setErrorFrom(L, folly::exceptionStr(exc)); 91 | } 92 | 93 | private: 94 | explicit Promise(uint64_t key); 95 | 96 | void validate(lua_State* L); 97 | void callPromiseMethod(lua_State* L, const char* method, int n); 98 | 99 | uint64_t key_; 100 | }; 101 | 102 | /** 103 | * Initialization. Call before using, for each lua_State that you intend 104 | * to use this in. 105 | */ 106 | void initFuture(lua_State* L); 107 | 108 | } // namespaces 109 | 110 | #endif /* FBLUALIB_FUTURE_H_ */ 111 | -------------------------------------------------------------------------------- /fblualib/README.md: -------------------------------------------------------------------------------- 1 | # fblualib C++ utilities 2 | 3 | This module provides a few C++ utilities wrapping the Lua API. 4 | `#include ` 5 | 6 | The module provides a series of functions named (and organized) as follows: 7 | for a type Foo (see below as to what types are allowed), we have: 8 | 9 | * `luaGetFoo(lua_State* L, int index)` returns a `folly::Optional`, which 10 | is set (non-empty) if the element on the stack at the given index can be 11 | converted to a Foo and empty otherwise 12 | * `luaGetFooChecked(lua_State* L, int index)` returns a `Foo` if the element 13 | on the stack at the given index can be converted to a Foo, and raises a 14 | Lua error otherwise 15 | * `luaGetFieldIfFoo(lua_State* L, int index, const char* field)` behaves 16 | similarly to `luaGetFoo`, but retrieves the data from a string-keyed field in 17 | a Lua table at the given index 18 | * `luaGetFieldIfFooChecked(lua_State* L, int index, const char* field)` 19 | behaves similarly to `luaGetFooChecked`, but retrieves a field as above 20 | 21 | Possible types (values of `Foo`) are: 22 | * `String`; the value type is `folly::StringPiece` 23 | * `Number`, templated by a numeric type; the value type is `T` (so 24 | `luaGetNumber(L, index)`, etc) 25 | * `Tensor`, templated by a numeric type; the value type is `thpp::Tensor` 26 | (so `luaGetTensor(L, index)`, etc) 27 | 28 | `luaGetString*` and `luaGetNumber*` support an extra `bool strict` argument 29 | (default `false`) indicating whether the data must be of the exact expected 30 | type (`strict = true`) or may be converted (`strict = false`); with 31 | `strict = false`, we will convert between numbers and strings, and will 32 | round floating-point values if integers are requested; with `strict = true`, 33 | we won't. 34 | 35 | There is also `luaPushTensor(lua_Stte* L, thpp::Tensor tensor)` which 36 | pushes a tensor on the stack (use the `lua_*` or `luaL_*` functions 37 | from the Lua standard library for other types). 38 | -------------------------------------------------------------------------------- /fblualib/Reactor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | // The actual Reactor class is in util/Reactor.cpp, but make sure that 20 | // gLoopingState is defined even if that isn't linked in. 21 | 22 | namespace fblualib { 23 | 24 | namespace detail { 25 | thread_local LoopingState gLoopingState; 26 | } // namespace detail 27 | 28 | } // namespaces 29 | -------------------------------------------------------------------------------- /fblualib/Reactor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | namespace fblualib { 23 | 24 | struct LoopingState { 25 | explicit LoopingState(lua_State* L = nullptr, folly::Executor* ex = nullptr) 26 | : L(L), executor(ex) { } 27 | 28 | lua_State* L; 29 | folly::Executor* executor; 30 | }; 31 | 32 | namespace detail { 33 | extern thread_local LoopingState gLoopingState; 34 | } // namespace detail 35 | 36 | /** 37 | * If there is a Reactor currently looping in this thread (using loop()), 38 | * return it. 39 | * 40 | * This is most useful for functions added using the Reactor's folly::Executor 41 | * interface. DO NOT CAPTURE THE CURRENT lua_State* WHEN SCHEDULING THESE 42 | * FUNCTIONS; the Reactor might loop in a different coroutine (with a different 43 | * lua_State*) and so you'll end up using the wrong lua_State. 44 | * 45 | * auto ex = ....; // get a pointer to the executor somehow 46 | * lua_State* L; 47 | * 48 | * DO NOT DO THIS: 49 | * 50 | * ! folly::via(ex) 51 | * ! .then( 52 | * ! [L] { 53 | * ! lua_pushinteger(L, 42); 54 | * ! lua_setglobal(L, "foo"); 55 | * ! }); 56 | * 57 | * DO THIS INSTEAD: 58 | * 59 | * folly::via(ex) 60 | * .then( 61 | * [] { 62 | * auto L = loopingState().L; 63 | * lua_pushinteger(L, 42); 64 | * lua_setglobal(L, "foo")p; 65 | * }); 66 | * 67 | * (loopingState().executor should be the same as ex, feel free to assert that) 68 | */ 69 | inline const LoopingState& loopingState() { return detail::gLoopingState; } 70 | 71 | } // namespaces 72 | -------------------------------------------------------------------------------- /fblualib/UserData.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | 21 | namespace fblualib { 22 | 23 | namespace detail { 24 | 25 | // UserData implementation: 26 | // 27 | // The metatable for a userdata object of type Derived (with base class Base): 28 | // 29 | // We use a few special fields in the metatable: 30 | // 31 | // _methods points to the _methods table (searched by the index trampoline) 32 | // 33 | // _base points to the metatable of the base class 34 | // 35 | // _cast_to_base is a function that takes a void* (pointer to Derived) and 36 | // casts it to a pointer to Base 37 | // 38 | // +-----------------+------------------------------+ 39 | // | __XXX | user-specified metamethod | 40 | // | __YYY | user-specified metamethod | 41 | // | __index | index trampoline | 42 | // | _methods | methods table ---------------+-----+ 43 | // | _base | metatable for base class | | 44 | // | _cast_to_base | cast function | | 45 | // +-----------------+------------------------------+ | 46 | // | 47 | // +-------------------------------------------------+ 48 | // | 49 | // v 50 | // +-----------------+------------------------------+ 51 | // | ZZZ | user-specified method | 52 | // | UUU | user-specified method | 53 | // | _index_handler_ | user-specified __index | 54 | // +-----------------+------------------------------+ 55 | // 56 | // All metamethods from a base class are copied into the derived class's 57 | // metatable. 58 | // 59 | // All methods from a base class are copied into the base class's methods 60 | // table. 61 | // 62 | // Field lookup (a:foo) proceeds by first looking into the _methods table, 63 | // then calling the _index_handler_ method if present. 64 | // 65 | // getUserData(L, index) will walk the _base chain, calling _cast_to_base 66 | // at each level, until the metatable of the object on the stack matches the 67 | // metatable registered for type T. 68 | 69 | // Upvalues: 70 | // 1 = methods table 71 | // 2 = index handler 72 | // 73 | // Called as __index, so arguments: 74 | // 1 = object 75 | // 2 = key 76 | int indexTrampoline(lua_State* L) { 77 | lua_pushvalue(L, 2); 78 | lua_gettable(L, lua_upvalueindex(1)); 79 | if (!lua_isnil(L, -1)) { 80 | return 1; // found it in methods table, done 81 | } 82 | lua_pop(L, 1); 83 | 84 | // call index handler 85 | lua_pushvalue(L, lua_upvalueindex(2)); 86 | lua_pushvalue(L, 1); 87 | lua_pushvalue(L, 2); 88 | lua_call(L, 2, 1); 89 | return 1; 90 | } 91 | 92 | namespace { 93 | 94 | // Copy all entries from the table at srcIdx to the table at destIdx 95 | void copyTable(lua_State* L, int destIdx, int srcIdx) { 96 | destIdx = luaRealIndex(L, destIdx); 97 | srcIdx = luaRealIndex(L, srcIdx); 98 | DCHECK_NE(destIdx, srcIdx); 99 | 100 | lua_pushnil(L); 101 | while (lua_next(L, srcIdx)) { 102 | // k v 103 | lua_pushvalue(L, -2); 104 | // k v k 105 | lua_insert(L, -2); 106 | // k k v 107 | lua_settable(L, destIdx); 108 | // k 109 | } 110 | } 111 | 112 | } // namespace 113 | 114 | void doRegisterBase(lua_State* L, lua_CFunction castFunction) { 115 | // derived_mt derived_methods base_mt 116 | lua_getfield(L, -1, "_methods"); 117 | 118 | // derived_mt derived_methods base_mt base_methods 119 | // Copy all metamethods and methods. 120 | copyTable(L, -3, -1); 121 | copyTable(L, -4, -2); 122 | 123 | // Add a _cast_to_base function in the metatable. 124 | lua_pushcfunction(L, castFunction); 125 | lua_setfield(L, -5, "_cast_to_base"); 126 | 127 | // Add a link to base metatable 128 | lua_pushvalue(L, -2); 129 | lua_setfield(L, -5, "_base"); 130 | 131 | // derived_mt derived_methods base_mt base_methods 132 | lua_pop(L, 2); 133 | } 134 | 135 | void* findClass(lua_State* L, void* ptr) { 136 | while (!lua_rawequal(L, -1, -2)) { 137 | // expected_mt actual_mt 138 | // Cast object to base 139 | lua_getfield(L, -1, "_cast_to_base"); 140 | if (lua_isnil(L, -1)) { 141 | lua_pop(L, 3); 142 | return nullptr; 143 | } 144 | lua_pushlightuserdata(L, ptr); 145 | // expected_mt actual_mt cast_method ptr 146 | lua_call(L, 1, 1); 147 | // expected_mt actual_mt new_ptr 148 | ptr = lua_touserdata(L, -1); 149 | lua_pop(L, 1); 150 | 151 | lua_getfield(L, -1, "_base"); 152 | if (lua_isnil(L, -1)) { 153 | // malformed? 154 | lua_pop(L, 3); 155 | return nullptr; 156 | } 157 | 158 | // expected_mt actual_mt base_mt 159 | lua_remove(L, -2); 160 | // expected_mt base_mt 161 | } 162 | lua_pop(L, 2); 163 | return ptr; 164 | } 165 | 166 | } // namespace detail 167 | 168 | } // namespaces 169 | -------------------------------------------------------------------------------- /fblualib/atomicvector/AtomicVectorTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #include "AtomicVector.h" 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | using namespace fblualib; 23 | 24 | // Torch tensors are a bit heavyweight to find real, CPU-level races. 25 | // Let's do integers instead. 26 | template<> 27 | struct Refcount { 28 | constexpr static int kMaxInt = 1000; 29 | static atomic m_counts[kMaxInt]; 30 | 31 | static void _check(int i) { 32 | // Reserve the value 0, because of puns in AtomicVector that 33 | // are meant to work with pointers. 34 | assert(i > 0 && i <= kMaxInt); 35 | } 36 | 37 | void inc(int i) { 38 | _check(i); 39 | m_counts[i - 1]++; 40 | } 41 | 42 | void dec(int i) { 43 | _check(i); 44 | assert(m_counts[i - 1] > 0); 45 | m_counts[i - 1]--; 46 | } 47 | 48 | int get(int i, bool /*debug*/ = false) const { 49 | _check(i); 50 | return m_counts[i - 1]; 51 | } 52 | 53 | void assertClear() const { 54 | for (int i = 0; i < kMaxInt; i++) { 55 | ASSERT_EQ(m_counts[i], 0); 56 | } 57 | } 58 | }; 59 | 60 | atomic Refcount::m_counts[Refcount::kMaxInt]; 61 | 62 | TEST(AtomicVector, append) { 63 | AtomicVector vec; 64 | Refcount rc; 65 | const int M = 100; 66 | for (int i = 0; i < M; i++) { 67 | vec.append(i * 3 + 1); 68 | } 69 | 70 | for (int i = 0; i < M; i++) { 71 | auto val = vec.read(i); 72 | assert(val == i * 3 + 1); 73 | rc.dec(val); 74 | } 75 | } 76 | 77 | TEST(AtomicVector, write) { 78 | AtomicVector vec; 79 | Refcount rc; 80 | // Some single-threaded write tests. 81 | bool sawExc = false; 82 | try { 83 | vec.write(1, 666); // Past end of vector 84 | } catch(runtime_error& re) { 85 | sawExc = true; 86 | } 87 | ASSERT_EQ(sawExc, true); 88 | 89 | // Append a few. 90 | const int N = 17; 91 | const int M = 1000; 92 | for (int i = 1; i < M; i++) { 93 | ASSERT_EQ(rc.get(i, true), 0); 94 | } 95 | for (int i = 0; i < N; i++) { 96 | vec.append(3 * i + 1); 97 | } 98 | 99 | for (int i = 0; i < N; i++) { 100 | ASSERT_EQ(rc.get(3 * i + 1), 1); 101 | } 102 | 103 | for (int i = 0; i < M; i++) { 104 | auto idx = i % N; 105 | vec.write(idx, i + 1); 106 | } 107 | 108 | for (int i = 0; i < N; i++) { 109 | auto val = vec.read(i); 110 | rc.dec(val); 111 | ASSERT_EQ(rc.get(val), 1); 112 | } 113 | } 114 | 115 | template 116 | int mptest(Lambda l) { 117 | vector threads; 118 | auto nprocs = sysconf(_SC_NPROCESSORS_ONLN); 119 | for (int i = 0; i < nprocs; i++) { 120 | threads.push_back(thread([l, i] { 121 | l(i); 122 | })); 123 | } 124 | 125 | for (auto& t: threads) { 126 | t.join(); 127 | } 128 | return nprocs; 129 | } 130 | 131 | TEST(AtomicVector, mpAppend) { 132 | Refcount rc; 133 | // No missed appends 134 | for (int i = 0; i < 12; i++) { // A few times 135 | ASSERT_EQ(rc.get(1, true), 0); 136 | AtomicVector lval; 137 | const int M = 1000; 138 | auto numThreads = mptest([&](int /*idx*/) { 139 | for (int i = 0; i < M; i++) { 140 | lval.append(1); 141 | } 142 | }); 143 | ASSERT_EQ(lval.size(), M * numThreads); 144 | ASSERT_EQ(rc.get(1), M * numThreads); 145 | } 146 | rc.assertClear(); 147 | } 148 | 149 | TEST(AtomicVector, mpRefcount) { 150 | Refcount rc; 151 | // Test refcount reasoning. 152 | for (int i = 0; i < 12; i++) { 153 | assert(rc.get(1, true) == 0); 154 | AtomicVector lval; 155 | auto numThreads = mptest([&](int /*idx*/) { lval.append(1); }); 156 | ASSERT_EQ(lval.size(), numThreads); 157 | assert(rc.get(1) == numThreads); 158 | 159 | (void) mptest([&](int idx) { 160 | lval.write(idx, idx + 1); 161 | }); 162 | for (int i = 0; i < numThreads; i++) { 163 | ASSERT_EQ(rc.get(i + 1), 1); 164 | } 165 | } 166 | rc.assertClear(); 167 | } 168 | -------------------------------------------------------------------------------- /fblualib/atomicvector/fb/atomicvector/_config.lua.in: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | return { 11 | clib = '@clib@', 12 | } 13 | 14 | -------------------------------------------------------------------------------- /fblualib/atomicvector/fb/atomicvector/init.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local clib = require('fb.atomicvector.clib') 11 | local torch = require('torch') 12 | local thrift = require('fb.thrift') 13 | 14 | local M = { 15 | create_float = clib.create_float, 16 | create_double = clib.create_double, 17 | create_int = clib.create_int, 18 | get = clib.get, 19 | destroy = clib.destroy, 20 | append = clib.append, 21 | } 22 | 23 | -- save() and load() take an atomic vector and a Lua file as inputs. 24 | function M.save(atom_vec, f) 25 | return clib.save(atom_vec, thrift.encode_file(f)) 26 | end 27 | 28 | function M.load(atom_vec, f) 29 | return clib.load(atom_vec, thrift.encode_file(f)) 30 | end 31 | 32 | -- load_legacy() reads the old file format. 33 | function M.load_legacy(atom_vec, f) 34 | local SerializationFormatVersionMajor = 1 35 | local SerializationFormatVersionMinor = 0 36 | local SerializationFormatMagic = "antigone thistle" 37 | 38 | local hdr = thrift.from_file(f) 39 | local function enforce(b, msg) 40 | if not b then 41 | error("atomicvector deserialization error: " .. msg) 42 | end 43 | end 44 | local function warnUnless(b, msg) 45 | if not b then 46 | print( "atomicvector deserializatio warningn: " .. msg) 47 | end 48 | end 49 | enforce(type(hdr) == 'table', "bad header type: " .. type(hdr)) 50 | enforce(hdr.magic == SerializationFormatMagic, 51 | "wrong magic field") 52 | enforce(hdr.major <= SerializationFormatVersionMajor, 53 | "too new version " .. hdr.major) 54 | enforce(type(hdr.size) == "number", 55 | "invalid size in header " .. hdr.size) 56 | warnUnless(hdr.major < SerializationFormatVersionMajor or 57 | hdr.minor <= SerializationFormatVersionMinor, 58 | ("restoring from new minor version %d.%d"): 59 | format(hdr.major, hdr.minor)) 60 | 61 | for i = 1, hdr.size do 62 | clib.append(atom_vec, thrift.from_file(f)) 63 | end 64 | end 65 | 66 | return M 67 | -------------------------------------------------------------------------------- /fblualib/atomicvector/rockspec/atomicvector-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2014, Facebook, Inc. 2 | -- All rights reserved. 3 | -- 4 | -- This source code is licensed under the BSD-style license found in the 5 | -- LICENSE file in the root directory of this source tree. An additional grant 6 | -- of patent rights can be found in the PATENTS file in the same directory. 7 | -- 8 | 9 | package = 'fbatomicvector' 10 | version = '0.1-1' 11 | source = { 12 | url = 'https://github.com/facebook/fblualib', 13 | } 14 | description = { 15 | summary = 'FB Basic Lua Utilities', 16 | detailed = [[ 17 | XXX 18 | ]], 19 | homepage = 'https://github.com/facebook/fblualib', 20 | license = 'BSD', 21 | } 22 | supported_platforms = { 23 | 'unix', 24 | } 25 | dependencies = { 26 | 'penlight >= 1.3.1', 27 | } 28 | source = { 29 | url = 'https://github.com/facebook/fblualib', 30 | dir = 'fblualib/atomicvector', 31 | } 32 | build = { 33 | type = 'command', 34 | build_command = [[ 35 | cmake -E make_directory build && 36 | cd build && 37 | cmake -DROCKS_PREFIX=$(PREFIX) \ 38 | -DROCKS_LUADIR=$(LUADIR) \ 39 | -DROCKS_LIBDIR=$(LIBDIR) \ 40 | .. && 41 | $(MAKE) 42 | ]], 43 | install_command = [[ 44 | cd build && $(MAKE) install 45 | ]], 46 | } 47 | 48 | -------------------------------------------------------------------------------- /fblualib/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Copyright (c) 2014, Facebook, Inc. 4 | # All rights reserved. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree. An additional grant 8 | # of patent rights can be found in the PATENTS file in the same directory. 9 | # 10 | 11 | set -o pipefail 12 | 13 | if [[ ! -r ./LuaUtils.h ]]; then 14 | echo "Please run from the fblualib subdirectory" >&2 15 | exit 1 16 | fi 17 | 18 | root=$(pwd) 19 | 20 | # Build C++ library component 21 | mkdir -p build 22 | cd build 23 | cmake .. 24 | make 25 | sudo make install 26 | 27 | rocks="util luaunit complex \ 28 | ffivector editline trepl debugger mattorch python thrift torch" 29 | version='0.1-1' 30 | for rock in $rocks; do 31 | cd $root/$rock 32 | # Unfortunately, luarocks doesn't like separating the "build" and 33 | # "install" phases, so we have to run as root. 34 | sudo luarocks make rockspec/fb$rock-$version.rockspec 35 | done 36 | -------------------------------------------------------------------------------- /fblualib/cmake/FindFBLuaLib.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # - Try to find fblualib 9 | # This will define 10 | # FBLUALIB_FOUND 11 | # FBLUALIB_INCLUDE_DIR 12 | # FBLUALIB_LIBRARIES 13 | 14 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 15 | 16 | INCLUDE(FindPackageHandleStandardArgs) 17 | 18 | FIND_LIBRARY(FBLUALIB_LIBRARY fblualib HINTS ${Torch_INSTALL_LIB}) 19 | FIND_PATH(FBLUALIB_INCLUDE_DIR "fblualib/LuaUtils.h" HINTS ${Torch_INSTALL_INCLUDE}) 20 | 21 | SET(FBLUALIB_LIBRARIES ${FBLUALIB_LIBRARY}) 22 | 23 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(FBLUALIB 24 | REQUIRED_ARGS FBLUALIB_INCLUDE_DIR FBLUALIB_LIBRARIES) 25 | -------------------------------------------------------------------------------- /fblualib/cmake/FindFolly.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # - Try to find folly 9 | # This will define 10 | # FOLLY_FOUND 11 | # FOLLY_INCLUDE_DIR 12 | # FOLLY_LIBRARIES 13 | 14 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 15 | 16 | INCLUDE(FindPackageHandleStandardArgs) 17 | 18 | FIND_LIBRARY(FOLLY_LIBRARY folly) 19 | FIND_PATH(FOLLY_INCLUDE_DIR "folly/String.h") 20 | 21 | SET(FOLLY_LIBRARIES ${FOLLY_LIBRARY}) 22 | 23 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Folly 24 | REQUIRED_ARGS FOLLY_INCLUDE_DIR FOLLY_LIBRARIES) 25 | -------------------------------------------------------------------------------- /fblualib/cmake/FindGlog.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # GLOG_FOUND 9 | # GLOG_INCLUDE_DIR 10 | # GLOG_LIBRARIES 11 | 12 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 13 | 14 | INCLUDE(FindPackageHandleStandardArgs) 15 | 16 | FIND_LIBRARY(GLOG_LIBRARY glog) 17 | FIND_PATH(GLOG_INCLUDE_DIR "glog/logging.h") 18 | 19 | SET(GLOG_LIBRARIES ${GLOG_LIBRARY}) 20 | 21 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 22 | Glog 23 | REQUIRED_ARGS GLOG_INCLUDE_DIR GLOG_LIBRARY) 24 | -------------------------------------------------------------------------------- /fblualib/cmake/FindMatIO.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # This will define 9 | # MATIO_FOUND 10 | # MATIO_INCLUDE_DIR 11 | # MATIO_LIBRARIES 12 | 13 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 14 | 15 | INCLUDE(FindPackageHandleStandardArgs) 16 | 17 | FIND_LIBRARY(MATIO_LIBRARY matio) 18 | FIND_PATH(MATIO_INCLUDE_DIR "matio.h") 19 | 20 | SET(MATIO_LIBRARIES ${MATIO_LIBRARY}) 21 | 22 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Folly 23 | REQUIRED_ARGS MATIO_INCLUDE_DIR MATIO_LIBRARIES) 24 | -------------------------------------------------------------------------------- /fblualib/cmake/FindNumPy.cmake: -------------------------------------------------------------------------------- 1 | # - Find the NumPy libraries 2 | # This module finds if NumPy is installed, and sets the following variables 3 | # indicating where it is. 4 | # 5 | # TODO: Update to provide the libraries and paths for linking npymath lib. 6 | # 7 | # NUMPY_FOUND - was NumPy found 8 | # NUMPY_VERSION - the version of NumPy found as a string 9 | # NUMPY_VERSION_MAJOR - the major version number of NumPy 10 | # NUMPY_VERSION_MINOR - the minor version number of NumPy 11 | # NUMPY_VERSION_PATCH - the patch version number of NumPy 12 | # NUMPY_VERSION_DECIMAL - e.g. version 1.6.1 is 10601 13 | # NUMPY_INCLUDE_DIRS - path to the NumPy include files 14 | 15 | #============================================================================ 16 | # Copyright 2012 Continuum Analytics, Inc. 17 | # 18 | # MIT License 19 | # 20 | # Permission is hereby granted, free of charge, to any person obtaining 21 | # a copy of this software and associated documentation files 22 | # (the "Software"), to deal in the Software without restriction, including 23 | # without limitation the rights to use, copy, modify, merge, publish, 24 | # distribute, sublicense, and/or sell copies of the Software, and to permit 25 | # persons to whom the Software is furnished to do so, subject to 26 | # the following conditions: 27 | # 28 | # The above copyright notice and this permission notice shall be included 29 | # in all copies or substantial portions of the Software. 30 | # 31 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 32 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 34 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 35 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 36 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 37 | # OTHER DEALINGS IN THE SOFTWARE. 38 | # 39 | #============================================================================ 40 | 41 | # Finding NumPy involves calling the Python interpreter 42 | if(NumPy_FIND_REQUIRED) 43 | find_package(PythonInterp REQUIRED) 44 | else() 45 | find_package(PythonInterp) 46 | endif() 47 | 48 | if(NOT PYTHONINTERP_FOUND) 49 | set(NUMPY_FOUND FALSE) 50 | return() 51 | endif() 52 | 53 | execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" 54 | "import numpy as n; print(n.__version__); print(n.get_include());" 55 | RESULT_VARIABLE _NUMPY_SEARCH_SUCCESS 56 | OUTPUT_VARIABLE _NUMPY_VALUES_OUTPUT 57 | ERROR_VARIABLE _NUMPY_ERROR_VALUE 58 | OUTPUT_STRIP_TRAILING_WHITESPACE) 59 | 60 | if(NOT _NUMPY_SEARCH_SUCCESS MATCHES 0) 61 | if(NumPy_FIND_REQUIRED) 62 | message(FATAL_ERROR 63 | "NumPy import failure:\n${_NUMPY_ERROR_VALUE}") 64 | endif() 65 | set(NUMPY_FOUND FALSE) 66 | return() 67 | endif() 68 | 69 | # Convert the process output into a list 70 | string(REGEX REPLACE ";" "\\\\;" _NUMPY_VALUES ${_NUMPY_VALUES_OUTPUT}) 71 | string(REGEX REPLACE "\n" ";" _NUMPY_VALUES ${_NUMPY_VALUES}) 72 | # Just in case there is unexpected output from the Python command. 73 | list(GET _NUMPY_VALUES -2 NUMPY_VERSION) 74 | list(GET _NUMPY_VALUES -1 NUMPY_INCLUDE_DIRS) 75 | 76 | string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" _VER_CHECK "${NUMPY_VERSION}") 77 | if("${_VER_CHECK}" STREQUAL "") 78 | # The output from Python was unexpected. Raise an error always 79 | # here, because we found NumPy, but it appears to be corrupted somehow. 80 | message(FATAL_ERROR 81 | "Requested version and include path from NumPy, got instead:\n${_NUMPY_VALUES_OUTPUT}\n") 82 | return() 83 | endif() 84 | 85 | # Make sure all directory separators are '/' 86 | string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIRS ${NUMPY_INCLUDE_DIRS}) 87 | 88 | # Get the major and minor version numbers 89 | string(REGEX REPLACE "\\." ";" _NUMPY_VERSION_LIST ${NUMPY_VERSION}) 90 | list(GET _NUMPY_VERSION_LIST 0 NUMPY_VERSION_MAJOR) 91 | list(GET _NUMPY_VERSION_LIST 1 NUMPY_VERSION_MINOR) 92 | list(GET _NUMPY_VERSION_LIST 2 NUMPY_VERSION_PATCH) 93 | string(REGEX MATCH "[0-9]*" NUMPY_VERSION_PATCH ${NUMPY_VERSION_PATCH}) 94 | math(EXPR NUMPY_VERSION_DECIMAL 95 | "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}") 96 | 97 | find_package_message(NUMPY 98 | "Found NumPy: version \"${NUMPY_VERSION}\" ${NUMPY_INCLUDE_DIRS}" 99 | "${NUMPY_INCLUDE_DIRS}${NUMPY_VERSION}") 100 | 101 | set(NUMPY_FOUND TRUE) 102 | 103 | -------------------------------------------------------------------------------- /fblualib/cmake/FindTHPP.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # - Try to find thpp 9 | # This will define 10 | # THPP_FOUND 11 | # THPP_INCLUDE_DIR 12 | # THPP_LIBRARIES 13 | 14 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 15 | 16 | INCLUDE(FindPackageHandleStandardArgs) 17 | 18 | FIND_LIBRARY(THPP_LIBRARY thpp) 19 | FIND_PATH(THPP_INCLUDE_DIR "thpp/Tensor.h") 20 | 21 | SET(THPP_LIBRARIES ${THPP_LIBRARY}) 22 | 23 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Folly 24 | REQUIRED_ARGS THPP_INCLUDE_DIR THPP_LIBRARIES) 25 | -------------------------------------------------------------------------------- /fblualib/cmake/FindThrift.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # THRIFT_FOUND 9 | # THRIFT_INCLUDE_DIR 10 | # THRIFT_LIBRARIES 11 | # 12 | # ADD_THRIFT2 and INSTALL_THRIFT2_HEADERS assume that you are using 13 | # MultiLevelIncludes. 14 | 15 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 16 | 17 | INCLUDE(FindPackageHandleStandardArgs) 18 | INCLUDE(MultiLevelIncludes) 19 | 20 | FIND_LIBRARY(THRIFT_LIBRARY thrift) 21 | FIND_LIBRARY(THRIFT_CPP2_LIBRARY thriftcpp2) 22 | FIND_PATH(THRIFT_INCLUDE_DIR "thrift/lib/cpp2/Thrift.h") 23 | 24 | SET(THRIFT_LIBRARIES ${THRIFT_LIBRARY} ${THRIFT_CPP2_LIBRARY}) 25 | 26 | # Add a Thrift2 file. 27 | # Add the source files to src_var in parent scope. 28 | # Does not support services (yet). 29 | FUNCTION(ADD_THRIFT2 src_var fn) 30 | GET_FILENAME_COMPONENT(dir ${fn} PATH) 31 | # NAME_WE = name without extension. Because this is the one place where 32 | # cmake developers have decided that verbosity is bad. 33 | GET_FILENAME_COMPONENT(bnwe ${fn} NAME_WE) 34 | SET(absroot "${MLI_INCLUDE_OUTPUT_DIR}/${dir}") 35 | SET(abspath "${absroot}/gen-cpp2") 36 | FILE(MAKE_DIRECTORY "${absroot}") 37 | SET(h_files "${abspath}/${bnwe}_data.h" 38 | "${abspath}/${bnwe}_types.h" 39 | "${abspath}/${bnwe}_types.tcc" 40 | "${abspath}/${bnwe}_constants.h") 41 | SET(src_files "${abspath}/${bnwe}_data.cpp" 42 | "${abspath}/${bnwe}_types.cpp" 43 | "${abspath}/${bnwe}_constants.cpp") 44 | GET_DIRECTORY_PROPERTY(includes INCLUDE_DIRECTORIES) 45 | FOREACH(d ${includes}) 46 | SET(include_args ${include_args} "-I" ${d}) 47 | ENDFOREACH() 48 | ADD_CUSTOM_COMMAND( 49 | OUTPUT ${h_files} ${src_files} 50 | COMMAND python ARGS 51 | -mthrift_compiler.main 52 | --gen cpp2:include_prefix 53 | ${include_args} 54 | "${CMAKE_CURRENT_SOURCE_DIR}/${fn}" 55 | 56 | DEPENDS "${fn}" 57 | WORKING_DIRECTORY "${absroot}") 58 | 59 | SET(${src_var} ${${src_var}} ${src_files} PARENT_SCOPE) 60 | ENDFUNCTION() 61 | 62 | # Install all Thrift2 headers from a directory 63 | # Does not support services (yet). 64 | FUNCTION(INSTALL_THRIFT2_HEADERS dir dest) 65 | SET(relpath "${dir}/gen-cpp2") 66 | SET(abspath "${MLI_INCLUDE_OUTPUT_DIR}/${relpath}") 67 | INSTALL(DIRECTORY "${abspath}/" 68 | DESTINATION "${dest}/${MLI_INCLUDE_RELATIVE_OUTPUT_DIR}/${relpath}" 69 | FILES_MATCHING 70 | PATTERN "*.h" 71 | PATTERN "*.tcc") 72 | 73 | SET(relpath "${dir}") 74 | SET(abspath "${CMAKE_CURRENT_SOURCE_DIR}/${relpath}") 75 | INSTALL(DIRECTORY "${abspath}/" 76 | DESTINATION "${dest}/${MLI_INCLUDE_RELATIVE_OUTPUT_DIR}/${relpath}" 77 | FILES_MATCHING 78 | PATTERN "*.thrift") 79 | ENDFUNCTION() 80 | 81 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 82 | Thrift 83 | REQUIRED_ARGS 84 | THRIFT_INCLUDE_DIR 85 | THRIFT_LIBRARY 86 | THRIFT_CPP2_LIBRARY) 87 | -------------------------------------------------------------------------------- /fblualib/cmake/MultiLevelIncludes.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | 8 | # Some projects are installed individually as part of a larger tree, but 9 | # include paths always reference the full include path in the tree. This 10 | # module makes it easier to do so. 11 | # 12 | # Suppose you have a source tree fblualib/thrift/submodule, which is built at 13 | # the submodule level (so you have fblualib/thrift/submodule/CMakeLists.txt) 14 | # Files inside submodule include each other (and files from other sibling 15 | # directories) with the full path: 16 | # 17 | # #include 18 | # #include 19 | # #include 20 | # #include 21 | # 22 | # MLI_SET_DEPTH(2) at the root of your CMakeLists.txt would set "../.." 23 | # as the include path (so fblualib is a subdirectory of that), making 24 | # the includes work. Also, it will set MLI_INCLUDE_OUTPUT_DIR and 25 | # MLI_INCLUDE_RELATIVE_OUTPUT_DIR to directories inside the build tree 26 | # where any generators should output header files so they can be found 27 | # via #include. (we recreate the lowest 2 levels of the hierarchy underneath 28 | # ${CMAKE_BINARY_DIR}) 29 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 30 | 31 | FUNCTION(MLI_SET_DEPTH level) 32 | SET(dirs) 33 | SET(dir ${CMAKE_SOURCE_DIR}) 34 | SET(relinc) 35 | FOREACH(i RANGE 1 ${level}) 36 | GET_FILENAME_COMPONENT(bn ${dir} NAME) 37 | GET_FILENAME_COMPONENT(dir ${dir} PATH) 38 | LIST(APPEND dirs ${bn}) 39 | SET(relinc "${relinc}/..") 40 | ENDFOREACH() 41 | LIST(REVERSE dirs) 42 | STRING(REPLACE ";" "/" relpath "${dirs}") 43 | SET(MLI_INCLUDE_OUTPUT_DIR 44 | "${CMAKE_BINARY_DIR}/${relpath}" 45 | PARENT_SCOPE) 46 | SET(MLI_INCLUDE_RELATIVE_OUTPUT_DIR 47 | "${relpath}" 48 | PARENT_SCOPE) 49 | INCLUDE_DIRECTORIES( 50 | "${CMAKE_SOURCE_DIR}/${relinc}" 51 | "${CMAKE_BINARY_DIR}") 52 | ENDFUNCTION() 53 | -------------------------------------------------------------------------------- /fblualib/complex/fb/complex/init.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | 9 | -- Rudimentary complex number support, building on top of LuaJIT's already 10 | -- existing support (1+2i is parsed correctly and produces a boxed double 11 | -- _Complex value) 12 | -- 13 | -- This provides basic mathematical operations and wrappers for the functions 14 | -- in 15 | 16 | local ffi = require('ffi') 17 | 18 | local M = {} 19 | 20 | local mt = {} 21 | local complex 22 | 23 | -- Ensure a number is of the complex type 24 | local function tocomplex(a) 25 | if ffi.istype(complex, a) then 26 | return a 27 | elseif type(a) == 'number' then 28 | return complex(a, 0) 29 | else 30 | error('Invalid type, numeric type expected') 31 | end 32 | end 33 | M.tocomplex = tocomplex 34 | 35 | -- Wrappers around functions 36 | local one_operand = { 37 | 'abs', 'acos', 'acosh', 'arg', 'asin', 'asinh', 'atan', 'atanh', 'cos', 38 | 'cosh', 'exp', 'log', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 39 | } 40 | 41 | local two_operand = { 42 | 'pow', 43 | } 44 | 45 | for _, fn in ipairs(one_operand) do 46 | local cname = 'c' .. fn 47 | ffi.cdef(string.format('double _Complex %s(double _Complex)', cname)) 48 | M[fn] = function(a) 49 | return ffi.C[cname](tocomplex(a)) 50 | end 51 | end 52 | 53 | for _, fn in ipairs(two_operand) do 54 | local cname = 'c' .. fn 55 | ffi.cdef(string.format( 56 | 'double _Complex %s(double _Complex, double _Complex)', cname)) 57 | M[fn] = function(a, b) 58 | return ffi.C[cname](tocomplex(a), tocomplex(b)) 59 | end 60 | end 61 | 62 | function M.conj(a) 63 | a = tocomplex(a) 64 | return complex(a.re, -a.im) 65 | end 66 | 67 | function mt.__add(a, b) 68 | a, b = tocomplex(a), tocomplex(b) 69 | return complex(a.re + b.re, a.im + b.im) 70 | end 71 | 72 | function mt.__sub(a, b) 73 | a, b = tocomplex(a), tocomplex(b) 74 | return complex(a.re - b.re, a.im - b.im) 75 | end 76 | 77 | function mt.__mul(a, b) 78 | a, b = tocomplex(a), tocomplex(b) 79 | return complex(a.re * b.re - a.im * b.im, 80 | a.re * b.im + a.im * b.re) 81 | end 82 | 83 | function mt.__div(a, b) 84 | a, b = tocomplex(a), tocomplex(b) 85 | local d = b.re * b.re + b.im * b.im 86 | return complex((a.re * b.re + a.im * b.im) / d, 87 | (a.im * b.re - a.re * b.im) / d) 88 | end 89 | 90 | mt.__pow = M.pow 91 | 92 | function mt.__unm(a) 93 | a = tocomplex(a) 94 | return complex(-a.re, -a.im) 95 | end 96 | 97 | complex = ffi.metatype('double _Complex', mt) 98 | 99 | return M 100 | -------------------------------------------------------------------------------- /fblualib/complex/rockspec/fbcomplex-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbcomplex' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Lua Debugger', 17 | detailed = [[ 18 | ]], 19 | homepage = 'https://github.com/facebook/fblualib', 20 | license = 'BSD', 21 | } 22 | supported_platforms = { 23 | 'unix', 24 | } 25 | dependencies = { 26 | 'penlight >= 1.3.1', 27 | } 28 | source = { 29 | url = 'https://github.com/facebook/fblualib', 30 | dir = 'fblualib/complex', 31 | } 32 | build = { 33 | type = 'builtin', 34 | modules = { 35 | ['fb.complex.init'] = 'fb/complex/init.lua', 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /fblualib/debugger/README.md: -------------------------------------------------------------------------------- 1 | # fb-debugger: A source-level Lua debugger 2 | 3 | This package implements a source-level Lua debugger. 4 | 5 | ## Usage 6 | 7 | You may enter the debugger in two different ways: 8 | * explicitly: at the point of interest, do 9 | ```lua 10 | local debugger = require('fb.debugger') 11 | debugger.enter() 12 | ``` 13 | and you will be dropped in the debugger 14 | * automatically when you hit an (uncaught) error: if using 15 | [fb.trepl](../trepl/README.md), you may set the environment variable 16 | `LUA_DEBUG_ON_ERROR` to `1`, and you'll be dropped in the debugger 17 | whenever your code raises an uncaught error. 18 | 19 | ## Debugger commands 20 | 21 | `help` will give you a list of commands, inspired by 22 | [gdb](http://www.gnu.org/software/gdb/). The following commands exist and behave 23 | similarly to their gdb counterparts: 24 | * `help` displays help 25 | * `where` / `backtrace` / `bt` displays the current stack trace (with a 26 | marker for the currently selected frame) 27 | * `frame` selects a given frame 28 | * `up` / `down` moves the currently selected frame up / down one 29 | * `b` / `break` sets a breakpoint at a given location (specified either as 30 | `:` or ``; the function name is looked up 31 | in the scope of the current frame) 32 | * `info breakpoints` lists breakpoints 33 | * `enable`, `disable`, `delete` enable, disable, and delete a breakpoint, 34 | respectively 35 | * `next` / `n` single-steps one line, skipping over function calls 36 | * `step` / `s` single-steps one line, descending into function calls 37 | * `finish` continues execution until the function in the currently selected 38 | frame returns 39 | * `continue` / `c` continues program execution until the next breakpoint, 40 | or until the next time the debugger is reentered (via `debugger.enter()` or 41 | automatically in case of error) 42 | * `locals` / `vlocals` shows locals in scope in the current frame; `vlocals` 43 | also shows values (verbose) 44 | * `globals` / `vglobals` shows all globals 45 | * `upvalues` / `vupvalues` shows the current function's upvalues 46 | * `exec` / `e` executes code in the scope of the current frame 47 | * `print` / `p` evaluates an expression in the scope of the current frame and 48 | prints the result 49 | * `list` / `l` lists source code (if available); by default it lists the 50 | function in the current frame, but it accepts a location argument just like 51 | `break`; just like gdb, repeating `l` without arguments continues listing 52 | the same file 53 | * `quit` / `q` quits the debugger; the program is resumed. 54 | 55 | Note that `locals`, `globals`, or `upvalues` will occasionally show a 56 | synthetic name for a variable (such as `_dbgl_tmp_4`). These indicate variables 57 | that have been shadowed in the current scope (and so their original name 58 | now refers to something else) or internal Lua temporaries (modifying those 59 | is ill-advised). 60 | -------------------------------------------------------------------------------- /fblualib/debugger/fb/debugger/types.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local pl = require('pl.import_into')() 11 | local utils = require('fb.debugger.utils') 12 | 13 | local M = {} 14 | 15 | local handled_types = {'table', 'userdata'} 16 | 17 | local type_handlers = {} 18 | for _, t in ipairs(handled_types) do 19 | type_handlers[t] = {} 20 | end 21 | 22 | local function verbose_type(obj) 23 | local t = type(obj) 24 | local handlers = type_handlers[t] 25 | 26 | if handlers then 27 | local mt = getmetatable(obj) 28 | for _, handler in ipairs(handlers) do 29 | local ok, result = pcall(handler, obj, mt) 30 | if ok and result then 31 | assert(type(result) == 'string') 32 | return result 33 | end 34 | end 35 | end 36 | 37 | return t 38 | end 39 | M.type = verbose_type 40 | 41 | local function add_type_handler(t, handler) 42 | table.insert(type_handlers[t], handler) 43 | end 44 | M.add_type_handler = add_type_handler 45 | 46 | -- default handlers 47 | 48 | -- file 49 | local function file_handler(obj, mt) 50 | local ft = io.type(obj) 51 | if ft then 52 | return ft 53 | end 54 | end 55 | add_type_handler('userdata', file_handler) 56 | 57 | -- module 58 | local function module_handler(obj) 59 | for k, v in pairs(package.loaded) do 60 | if v == obj then 61 | return 'module' 62 | end 63 | end 64 | end 65 | add_type_handler('table', module_handler) 66 | 67 | -- Penlight class 68 | local function pl_class_handler(obj, mt) 69 | if not mt then return end 70 | local cls = obj._class 71 | if cls.class_of then 72 | if cls == obj then 73 | if cls._name then 74 | return 'cls:' .. cls._name 75 | else 76 | return 'pl_class' 77 | end 78 | elseif cls == mt then 79 | if cls._name then 80 | return cls._name 81 | else 82 | return 'pl_object' 83 | end 84 | end 85 | end 86 | end 87 | add_type_handler('table', pl_class_handler) 88 | 89 | local function empty_string() 90 | return '' 91 | end 92 | 93 | local function default_printer(obj, max_len) 94 | local more_suffix = '...' 95 | assert(max_len == nil or max_len >= #more_suffix) 96 | local s = tostring(obj) 97 | if #s > max_len then 98 | s = string.sub(s, 1, max_len - #more_suffix) 99 | s = s .. more_suffix 100 | end 101 | return s 102 | end 103 | 104 | local printers_for_type = {} 105 | 106 | local function add_to_table(table, keys, value) 107 | if type(keys) == 'table' then 108 | for _, key in ipairs(keys) do 109 | table[key] = value 110 | end 111 | else 112 | table[keys] = value 113 | end 114 | end 115 | 116 | local function add_printer(types, printer) 117 | add_to_table(printers_for_type, types, printer) 118 | end 119 | M.add_printer = add_printer 120 | 121 | local printers_for_pattern = {} 122 | 123 | local function add_printer_for_pattern(patterns, printer) 124 | add_to_table(printers_for_pattern, patterns, printer) 125 | end 126 | M.add_printer_for_pattern = add_printer_for_pattern 127 | 128 | -- don't truncate number representations 129 | add_printer('number', tostring) 130 | add_printer('string', utils.string_repr) 131 | add_printer('boolean', tostring) 132 | 133 | local function pretty_print(obj, max_len) 134 | local t = verbose_type(obj) 135 | local printer = printers_for_type[t] 136 | if printer then 137 | return printer(obj, max_len) 138 | end 139 | for pattern, printer in pairs(printers_for_pattern) do 140 | if string.match(t, pattern) then 141 | return printer(obj, max_len) 142 | end 143 | end 144 | return default_printer(obj, max_len) 145 | end 146 | M.pretty_print = pretty_print 147 | 148 | -- Torch-specific code, if torch is installed 149 | local ok, torch = pcall(require, 'torch') 150 | if ok then 151 | -- Torch class 152 | local function torch_class_handler(obj, mt) 153 | if mt and obj.__typename then 154 | return obj.__typename 155 | end 156 | end 157 | add_type_handler('userdata', torch_class_handler) 158 | 159 | add_printer_for_pattern( 160 | {'^torch%.%a+Tensor$', '^torch%.%a+Storage$'}, 161 | function(obj) 162 | local sz = obj:size():totable() 163 | if #sz == 0 then 164 | return 'empty' 165 | else 166 | return pl.stringx.join('x', sz) 167 | end 168 | end) 169 | end 170 | 171 | return M 172 | -------------------------------------------------------------------------------- /fblualib/debugger/fb/debugger/utils.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local pl = require('pl.import_into')() 11 | local printf = pl.utils.printf 12 | 13 | local M = {} 14 | 15 | local function plural(n, s, p) 16 | if n == 1 then 17 | return s 18 | elseif not p then 19 | return s .. 's' 20 | else 21 | return p 22 | end 23 | end 24 | M.plural = plural 25 | 26 | local function print_numbered(str, b, context, current_line) 27 | if context then 28 | context = context - 1 29 | end 30 | local lines = pl.stringx.splitlines(str) 31 | 32 | if not b then 33 | b = 1 34 | if current_line and context then 35 | b = math.max(b, math.floor(current_line - context / 2)) 36 | end 37 | end 38 | 39 | local e = #lines 40 | if context then 41 | e = math.min(e, b + context + 1) 42 | end 43 | 44 | for i = b, e do 45 | local line = lines[i] 46 | local line_marker = ' ' 47 | if i == current_line then 48 | line_marker = '>' 49 | end 50 | printf('%5d %s %s\n', i, line_marker, line) 51 | end 52 | 53 | return e + 1 54 | end 55 | M.print_numbered = print_numbered 56 | 57 | local translate_table = { 58 | [string.byte("'")] = "''", 59 | [string.byte('\\')] = '\\\\', 60 | [string.byte('\a')] = '\\a', 61 | [string.byte('\b')] = '\\b', 62 | [string.byte('\f')] = '\\f', 63 | [string.byte('\n')] = '\\n', 64 | [string.byte('\r')] = '\\r', 65 | [string.byte('\t')] = '\\t', 66 | [string.byte('\v')] = '\\v', 67 | } 68 | 69 | local function string_repr(s, max_len) 70 | local more_suffix = '...' 71 | if max_len then 72 | assert(max_len >= #more_suffix + 2) 73 | max_len = max_len - 2 74 | end 75 | local cut = false 76 | local out = {} 77 | local len = 0 78 | for i = 1, #s do 79 | local b = s:byte(i) 80 | local t = translate_table[b] 81 | if not t then 82 | if b >= 32 and b <= 126 then 83 | t = string.char(b) 84 | else 85 | t = string.format('\\%03d', b) 86 | end 87 | end 88 | table.insert(out, t) 89 | len = len + #t 90 | if max_len and len > max_len then 91 | while len + #more_suffix > max_len do 92 | t = out[#out] 93 | table.remove(out) 94 | len = len - #t 95 | end 96 | cut = true 97 | break 98 | end 99 | end 100 | local out_str = "'" .. pl.stringx.join('', out) .. "'" 101 | if cut then 102 | out_str = out_str .. more_suffix 103 | end 104 | return out_str 105 | end 106 | M.string_repr = string_repr 107 | 108 | return M 109 | -------------------------------------------------------------------------------- /fblualib/debugger/rockspec/fbdebugger-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbdebugger' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Lua Debugger', 17 | detailed = [[ 18 | This is a general-purpose debugger for Lua. Its command syntax is 19 | inspired by gdb, and it has special support for printing Torch tensors 20 | (but Torch is not required). Requires LuaJIT 2.0+. 21 | ]], 22 | homepage = 'https://github.com/facebook/fblualib', 23 | license = 'BSD', 24 | } 25 | supported_platforms = { 26 | 'unix', 27 | } 28 | dependencies = { 29 | 'fbutil >= 0.1', 30 | 'fbeditline >= 0.1', 31 | 'penlight >= 1.3.1', 32 | } 33 | source = { 34 | url = 'https://github.com/facebook/fblualib', 35 | dir = 'fblualib/debugger', 36 | } 37 | build = { 38 | type = 'builtin', 39 | modules = { 40 | ['fb.debugger.breakpoint'] = 'fb/debugger/breakpoint.lua', 41 | ['fb.debugger.init'] = 'fb/debugger/init.lua', 42 | ['fb.debugger.types'] = 'fb/debugger/types.lua', 43 | ['fb.debugger.utils'] = 'fb/debugger/utils.lua', 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /fblualib/editline/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | ENABLE_TESTING() 12 | 13 | SET(CMAKE_MODULE_PATH 14 | "${CMAKE_CURRENT_SOURCE_DIR}/../cmake" 15 | "${CMAKE_MODULE_PATH}") 16 | 17 | INCLUDE(MultiLevelIncludes) 18 | MLI_SET_DEPTH(2) 19 | 20 | FIND_LIBRARY(libedit NAMES edit libedit libedit.so.2) 21 | IF(NOT libedit) 22 | MESSAGE(FATAL_ERROR "libedit required") 23 | ENDIF(NOT libedit) 24 | 25 | CONFIGURE_FILE( 26 | "fb/editline/_config.lua.in" 27 | "fb/editline/_config.lua" 28 | @ONLY) 29 | 30 | INSTALL( 31 | DIRECTORY "fb" 32 | DESTINATION "${ROCKS_LUADIR}" 33 | FILES_MATCHING 34 | PATTERN "*.lua") 35 | 36 | INSTALL( 37 | DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/fb" 38 | DESTINATION "${ROCKS_LUADIR}" 39 | FILES_MATCHING 40 | PATTERN "*.lua") 41 | -------------------------------------------------------------------------------- /fblualib/editline/README.md: -------------------------------------------------------------------------------- 1 | # fb-editline: [libedit](http://thrysoee.dk/editline/) bindings for LuaJIT 2 | 3 | ## Basic bindings 4 | The core of this module is the `EditLine` class, instantiated with a 5 | configuration table (described below). The `read` method returns the next 6 | line read from the terminal, or `nil` if the user entered the EOF 7 | character (usually Ctrl-D). 8 | 9 | ```lua 10 | local editline = require('fb.editline') 11 | local el_loop = editline.EditLine({ 12 | prompt = 'hello> ', 13 | }) 14 | 15 | while true do 16 | local line = el_loop:read() 17 | 18 | -- process line 19 | el_loop:add_history(line) 20 | end 21 | ``` 22 | 23 | The configuration table contains: 24 | * `prompt`: the prompt to display at the beginning of each line 25 | * `prompt_func`: alternatively, this is a function called at the beginning 26 | of each line that should return the prompt; if `nil`, the value of 27 | `prompt` is used; if `prompt` is also `nil`, the prompt is `> ' 28 | * `history_file`: file name to save history to, if desired 29 | * `word_break`: string of word break characters (good default) 30 | * `auto_history`: if true, lines are automatically added to history; 31 | otherwise, call `add_history` yourself 32 | * `complete`: completion function, called whenever the user types the 33 | completion key (by default Tab); `init.lua` has more details 34 | * `max_matches`: the maximum number of matches to display when completing; 35 | if there are more matches, the user gets a confirmation prompt 36 | 37 | ## Word completion 38 | 39 | A good completion function is provided: 40 | 41 | ```lua 42 | local completer = require('fb.editline.completer') 43 | local el_loop = editline.EditLine({ 44 | prompt = 'hello> ', 45 | complete = completer.complete, 46 | }) 47 | ``` 48 | 49 | The completer completes values appropriately (local and global variables; Lua 50 | keywords; if `foo` is a table / module, `foo.` will complete with keys in 51 | `foo`) and strings as files in the filesystem (try `"./`) 52 | -------------------------------------------------------------------------------- /fblualib/editline/editline_test.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local editline = require('fb.editline') 11 | local completer = require('fb.editline.completer') 12 | 13 | local el = editline.EditLine({ 14 | prompt = 'hello> ', 15 | history_file=os.getenv('HOME') .. '/.foo_history', 16 | complete = completer.complete, 17 | auto_history = true, 18 | }) 19 | 20 | while true do 21 | local line = el:read() 22 | if not line then 23 | break 24 | end 25 | print(line) 26 | end 27 | -------------------------------------------------------------------------------- /fblualib/editline/fb/editline/_config.lua.in: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | return { 11 | libedit = '@libedit@', 12 | } 13 | -------------------------------------------------------------------------------- /fblualib/editline/rockspec/fbeditline-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbeditline' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB bindings for editline', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'fbutil >= 0.1', 28 | 'penlight >= 1.3.1', 29 | 'luafilesystem >= 1.6', 30 | } 31 | source = { 32 | url = 'https://github.com/facebook/fblualib', 33 | dir = 'fblualib/editline', 34 | } 35 | build = { 36 | type = 'command', 37 | build_command = [[ 38 | cmake -E make_directory build && 39 | cd build && 40 | cmake -DROCKS_PREFIX=$(PREFIX) \ 41 | -DROCKS_LUADIR=$(LUADIR) \ 42 | -DROCKS_LIBDIR=$(LIBDIR) \ 43 | .. && 44 | $(MAKE) 45 | ]], 46 | install_command = [[ 47 | cd build && $(MAKE) install 48 | ]], 49 | } 50 | -------------------------------------------------------------------------------- /fblualib/ffivector/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | ENABLE_TESTING() 12 | 13 | SET(CMAKE_MODULE_PATH 14 | "${CMAKE_CURRENT_SOURCE_DIR}/../cmake" 15 | "${CMAKE_MODULE_PATH}") 16 | 17 | INCLUDE(MultiLevelIncludes) 18 | MLI_SET_DEPTH(2) 19 | 20 | FIND_PACKAGE(Folly REQUIRED) 21 | 22 | INCLUDE_DIRECTORIES( 23 | ${FOLLY_INCLUDE_DIR} 24 | ) 25 | 26 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") 27 | 28 | SET(src 29 | FFIVector.cpp 30 | ) 31 | 32 | ADD_LIBRARY(fbffivector MODULE ${src}) 33 | TARGET_LINK_LIBRARIES(fbffivector ${FOLLY_LIBRARIES}) 34 | 35 | 36 | INSTALL(TARGETS fbffivector 37 | LIBRARY DESTINATION "${ROCKS_LIBDIR}") 38 | 39 | INSTALL( 40 | DIRECTORY "fb" 41 | DESTINATION "${ROCKS_LUADIR}" 42 | FILES_MATCHING 43 | PATTERN "*.lua") 44 | 45 | INSTALL( 46 | DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/fb" 47 | DESTINATION "${ROCKS_LUADIR}" 48 | FILES_MATCHING 49 | PATTERN "*.lua") 50 | -------------------------------------------------------------------------------- /fblualib/ffivector/FFIVector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | extern "C" { 17 | 18 | // NOTE: this must match the ffi.cdef in ffivector.lua 19 | 20 | typedef struct { 21 | size_t elementSize; 22 | size_t size; 23 | size_t capacity; 24 | void* data; 25 | } FFIVector; 26 | 27 | int ffivector_create(FFIVector* v, size_t elementSize, size_t initialCapacity); 28 | void ffivector_destroy(FFIVector* v); 29 | int ffivector_reserve(FFIVector* v, size_t n); 30 | int ffivector_resize(FFIVector* v, size_t n); 31 | 32 | } 33 | 34 | int ffivector_create(FFIVector* v, size_t elementSize, size_t initialCapacity) { 35 | v->elementSize = elementSize; 36 | v->size = 0; 37 | v->capacity = initialCapacity; 38 | if (initialCapacity != 0) { 39 | v->data = malloc(initialCapacity * elementSize); 40 | if (!v->data) { 41 | return -ENOMEM; 42 | } 43 | } else { 44 | v->data = nullptr; 45 | } 46 | return 0; 47 | } 48 | 49 | void ffivector_destroy(FFIVector* v) { 50 | free(v->data); 51 | } 52 | 53 | int ffivector_reserve(FFIVector* v, size_t n) { 54 | if (n <= v->capacity) { 55 | return 0; 56 | } 57 | 58 | try { 59 | if (v->data) { 60 | v->data = folly::smartRealloc( 61 | v->data, 62 | v->size * v->elementSize, 63 | v->capacity * v->elementSize, 64 | n * v->elementSize); 65 | } else { 66 | v->data = folly::checkedMalloc(n * v->elementSize); 67 | } 68 | } catch (const std::bad_alloc&) { 69 | return -ENOMEM; 70 | } 71 | 72 | v->capacity = malloc_usable_size(v->data) / v->elementSize; 73 | DCHECK_GE(v->capacity, n); 74 | return 0; 75 | } 76 | 77 | int ffivector_resize(FFIVector* v, size_t n) { 78 | if (n > v->capacity) { 79 | // 1.5x growth factor 80 | size_t newCapacity = std::max(n, 1 + v->size * 3 / 2); 81 | int r = ffivector_reserve(v, newCapacity); 82 | if (r != 0) { 83 | return r; 84 | } 85 | } 86 | 87 | if (n > v->size) { 88 | memset(static_cast(v->data) + v->size * v->elementSize, 89 | 0, 90 | (n - v->size) * v->elementSize); 91 | } 92 | 93 | v->size = n; 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /fblualib/ffivector/README.md: -------------------------------------------------------------------------------- 1 | # fb-ffivector: Vector of POD types or strings 2 | 3 | This package implements a vector (1-dimensional array) of numbers, strings, 4 | or other [FFI](http://luajit.org/ext_ffi.html) plain-old-data (POD) types. 5 | These vectors (and their contents) do not count toward the Lua heap limit 6 | (which is 1GiB in LuaJIT 2.0.x). 7 | 8 | ## Allowed element types 9 | 10 | Any FFI cdata object is allowed, as long as it can be moved safely in 11 | memory by calling `memmove()` (or equivalent); objects that store pointers to 12 | (parts of) themselves cannot be used. Here's a contrived example of an invalid 13 | object: 14 | 15 | ```c 16 | struct Foo { 17 | int elements[100]; 18 | int* currentElement; 19 | }; 20 | 21 | Foo foo; 22 | foo.currentElement = &(foo.elements[20]); 23 | ``` 24 | 25 | `foo.currentElement` points within `foo`, and therefore the pointer would 26 | become invalid if `foo` were relocated to another address. 27 | 28 | ## Creating a vector 29 | 30 | There is one main function (assuming `local ffivector = require('fb.ffivector')`): 31 | 32 | ```lua 33 | ffivector.new(ctype, initial_capacity, index, newindex, destructor) 34 | ``` 35 | 36 | * `ctype` is the type of the elements, either a FFI ctype 37 | (`ffi.typeof('double')`) or a string containing a C declaration (`double` or 38 | `struct { double x; int y; }`) 39 | * `initial_capacity` is the initial capacity of the vector, default 0 40 | * `index` is an optional function that will be applied to elements as they 41 | are retrieved _from_ the vector. For example, a vector of `int` could use 42 | `tonumber`here, and then `v[42]` would return a Lua number rather than a FFI 43 | `int`. The vector of strings implementation (see below) uses this to convert 44 | from the internal representation to a Lua string (created on the fly). 45 | * `newindex` is the opposite; it's an optional function that will be applied 46 | to new values as they are added to the vector. The vector of strings 47 | implementation uses this to convert from Lua strings to the internal 48 | representation. Vectors of FFI numeric types don't need this, as LuaJIT 49 | performs the conversion from Lua number to FFI numeric types automatically. 50 | * `destructor` is an optional function that is called on each element as it is 51 | destroyed (when the vector itself is GCed, or when an element is overwritten). 52 | The vector of strings implementation uses this to free memory. 53 | 54 | For convenience, we also provide functions to create vectors of standard 55 | C numeric types: `new_char`, `new_unsigned_long`, `new_int`, `new_uint64_t`, 56 | `new_float`, etc. The vectors such created have `tonumber` as the index 57 | function, and so precision is limited by Lua numbers. 58 | 59 | We also provide `new_string`, which creates a vector of strings. The strings 60 | are stored outside the Lua heap, and a new Lua string is created (copied from 61 | the vector) on demand whenever you access an element. 62 | 63 | ## Vector methods 64 | 65 | Vectors support the `#` operator (returning the size, that is, the number 66 | of elements currently in the vector), the usual (1-based) indexing, and the 67 | following methods: 68 | 69 | * `capacity()` returns the capacity (the number of currently allocated 70 | elements); this may be greater than the vector's size. 71 | * `reserve(n)` changes the vector's capacity to ensure that the size may grow 72 | up to `n` elements without reallocation 73 | * `resize(n)` grows (or shrinks) the vector so that its size is exactly `n`; 74 | if `n` is greater than the current size, the new elments are initialized to 0; 75 | if `n` is less than the current size, the elements past `n` are destroyed. 76 | 77 | As a special case, we support assigning one element past the end of the vector, 78 | which will grow the vector (as if by calling `vec:resize(#vec + 1)`), as 79 | assigning one element past the end is a common pattern for growing Lua 80 | list-like tables. 81 | -------------------------------------------------------------------------------- /fblualib/ffivector/fb/ffivector/_config.lua.in: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | return { 11 | clib = '@clib@', 12 | } 13 | -------------------------------------------------------------------------------- /fblualib/ffivector/rockspec/fbffivector-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbffivector' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Basic Lua Utilities', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'penlight >= 1.3.1', 28 | } 29 | source = { 30 | url = 'https://github.com/facebook/fblualib', 31 | dir = 'fblualib/ffivector', 32 | } 33 | build = { 34 | type = 'command', 35 | build_command = [[ 36 | cmake -E make_directory build && 37 | cd build && 38 | cmake -DROCKS_PREFIX=$(PREFIX) \ 39 | -DROCKS_LUADIR=$(LUADIR) \ 40 | -DROCKS_LIBDIR=$(LIBDIR) \ 41 | .. && 42 | $(MAKE) 43 | ]], 44 | install_command = [[ 45 | cd build && $(MAKE) install 46 | ]], 47 | } 48 | -------------------------------------------------------------------------------- /fblualib/ffivector/test/ffivector_test.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | require('fb.luaunit') 11 | 12 | local ffivector = require('fb.ffivector') 13 | 14 | function testIntFFIVector() 15 | local v = ffivector.new_int() 16 | v:resize(42) 17 | assertEquals(42, #v) 18 | assertTrue(v:capacity() >= 42) 19 | 20 | for i = 1, 42 do 21 | assertEquals(0, v[i]) 22 | end 23 | 24 | assertError(function() return v[0] end) 25 | assertError(function() return v[43] end) 26 | 27 | for i = 1, 42 do 28 | v[i] = i * 10 29 | end 30 | 31 | for i = 1, 42 do 32 | assertEquals(i * 10, v[i]) 33 | end 34 | end 35 | 36 | function testStructFFIVector() 37 | local v = ffivector.new('struct { int a; int64_t b; }') 38 | 39 | v:resize(42) 40 | for i = 1, 42 do 41 | p = v[i] -- it's a reference! 42 | p.a = i * 10 43 | p.b = i * 100 44 | end 45 | 46 | for i = 1, 42 do 47 | assertEquals(i * 10, v[i].a) 48 | assertEquals(i * 100, tonumber(v[i].b)) 49 | end 50 | end 51 | 52 | function testStringFFIVector() 53 | local v = ffivector.new_string() 54 | 55 | v:resize(42) 56 | for i = 1, 42 do 57 | v[i] = 'hello ' .. tostring(i) 58 | end 59 | collectgarbage() -- temp strings should no longer be allocated 60 | 61 | for i = 1, 42 do 62 | assertEquals('hello ' .. tostring(i), v[i]) 63 | end 64 | end 65 | 66 | function testStringFFIVectorDestruction() 67 | do 68 | local v = ffivector.new_string() 69 | end 70 | collectgarbage() 71 | end 72 | 73 | function testFFIVectorDestruction() 74 | local destructor_count = 0 75 | 76 | do 77 | local v = ffivector.new( 78 | 'int', 0, tonumber, nil, 79 | function(x) destructor_count = destructor_count + 1 end) 80 | v:resize(42) 81 | assertEquals(0, destructor_count) 82 | 83 | v[10] = 10 84 | assertEquals(1, destructor_count) 85 | 86 | v[42] = 10 87 | assertEquals(2, destructor_count) 88 | 89 | v[43] = 10 90 | assertEquals(2, destructor_count) 91 | assertEquals(43, #v) 92 | 93 | v:resize(50) 94 | assertEquals(2, destructor_count) 95 | assertEquals(50, #v) 96 | 97 | v:resize(40) 98 | assertEquals(12, destructor_count) 99 | assertEquals(40, #v) 100 | end 101 | collectgarbage() 102 | 103 | assertEquals(52, destructor_count) 104 | end 105 | 106 | LuaUnit:main() 107 | -------------------------------------------------------------------------------- /fblualib/luaunit/README.md: -------------------------------------------------------------------------------- 1 | # Facebook port of [LuaUnit](http://phil.freehackers.org/programs/luaunit/) 2 | 3 | The interface is very similar to LuaUnit, with a few minor differences: 4 | * if the `LUAUNIT_LIST_TESTS` environment variable is set, LuaUnit will list 5 | tests rather than running them 6 | * the `LUAUNIT_OUTPUT_TYPE` environment variable dictates the output format 7 | -------------------------------------------------------------------------------- /fblualib/luaunit/rockspec/fbluaunit-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbluaunit' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Lua Debugger', 17 | detailed = [[ 18 | FB fork of LuaUnit. 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'lua-cjson >= 2.1.0', 28 | } 29 | source = { 30 | url = 'https://github.com/facebook/fblualib', 31 | dir = 'fblualib/fbluaunit', 32 | } 33 | build = { 34 | type = 'builtin', 35 | modules = { 36 | ['fb.luaunit.init'] = 'fb/luaunit/init.lua', 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /fblualib/mattorch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | ENABLE_TESTING() 12 | 13 | # Torch messes this up 14 | SET(SAVED_CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) 15 | 16 | SET(CMAKE_MODULE_PATH 17 | "${CMAKE_CURRENT_SOURCE_DIR}/../cmake" 18 | "${CMAKE_MODULE_PATH}") 19 | 20 | INCLUDE(MultiLevelIncludes) 21 | MLI_SET_DEPTH(2) 22 | 23 | FIND_PACKAGE(Folly REQUIRED) 24 | FIND_PACKAGE(Glog REQUIRED) 25 | FIND_PACKAGE(Torch REQUIRED) 26 | FIND_PACKAGE(THPP REQUIRED) 27 | FIND_PACKAGE(FBLuaLib REQUIRED) 28 | FIND_PACKAGE(MatIO REQUIRED) 29 | 30 | INCLUDE_DIRECTORIES( 31 | ${FOLLY_INCLUDE_DIR} 32 | ${GLOG_INCLUDE_DIR} 33 | ${THPP_INCLUDE_DIR} 34 | ${FBLUALIB_INCLUDE_DIR} 35 | ${MATIO_INCLUDE_DIR} 36 | ) 37 | 38 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") 39 | 40 | SET(src 41 | MatTorch.cpp 42 | ) 43 | 44 | ADD_LIBRARY(lua_module MODULE ${src}) 45 | SET_TARGET_PROPERTIES(lua_module PROPERTIES 46 | PREFIX "" 47 | OUTPUT_NAME "lib" 48 | COMPILE_DEFINITIONS "LUAOPEN=luaopen_fb_mattorch_lib") 49 | TARGET_LINK_LIBRARIES(lua_module 50 | dl ${FOLLY_LIBRARIES} ${GLOG_LIBRARIES} ${THPP_LIBRARIES} 51 | ${FBLUALIB_LIBRARIES} ${MATIO_LIBRARIES}) 52 | 53 | SET(CMAKE_INSTALL_PREFIX ${SAVED_CMAKE_INSTALL_PREFIX}) 54 | 55 | INSTALL(TARGETS lua_module 56 | DESTINATION "${ROCKS_LIBDIR}/fb/mattorch") 57 | 58 | INSTALL(DIRECTORY "fb" 59 | DESTINATION "${ROCKS_LUADIR}" 60 | FILES_MATCHING 61 | PATTERN "*.lua") 62 | -------------------------------------------------------------------------------- /fblualib/mattorch/README.md: -------------------------------------------------------------------------------- 1 | # fb-mattorch: Read and write Matlab files (without Matlab) 2 | 3 | This is an alternative to the 4 | [mattorch](https://github.com/clementfarabet/lua---mattorch) package that 5 | provides a subset of functionality (it only permits reading and writing 6 | of Matlab files) but does not require that you have Matlab installed; 7 | it uses the open-source [MAT File I/O Library](http://matio.sourceforge.net/) 8 | instead. 9 | 10 | ## Usage 11 | 12 | ```lua 13 | local mattorch = require('fb.mattorch') 14 | 15 | -- Load all variables from a Matlab file; returns a table of the form 16 | -- {name = value}, where values are torch Tensors 17 | local vars = mattorch.load('foo.mat') 18 | 19 | -- Save all variables from a Matlab file; given a table of the form 20 | -- {name = value}, where values are torch Tensors, writes them to 21 | -- a Matlab file 22 | mattorch.save('bar.mat', vars) 23 | 24 | -- Save one single tensor to a Matlab file under the uninspired name 'x' 25 | -- equivalent to mattorch.save('baz.mat', {x = var}) 26 | mattorch.save('baz.mat', var) 27 | ``` 28 | -------------------------------------------------------------------------------- /fblualib/mattorch/fb/mattorch/init.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local lib = require('fb.mattorch.lib') 11 | local torch = require('torch') 12 | 13 | local M = {} 14 | 15 | -- load(path) 16 | -- Load all vars in a Matlab file at path as a table of {name: tensor} 17 | M.load = lib.load 18 | 19 | -- save(path, vars, [ver]) 20 | -- Save all vars into a Matlab file at path. 21 | -- 22 | -- If vars is a table, all values in the table are saved under their 23 | -- corresponding names. 24 | -- If vars is a tensor, it is saved under the uninspired name 'x'. 25 | -- 26 | -- If given, ver must be a string indicating the Matlab file version to 27 | -- generate: '4', '5', or '7.3'. The default is determined by the way 28 | -- the underlying matio library was configured on your system, usually 5. 29 | function M.save(path, vars, ver) 30 | if type(vars) == 'userdata' and torch.typename(vars) then 31 | lib.saveTensor(path, vars, ver) 32 | elseif type(vars) == 'table' then 33 | lib.saveTable(path, vars, ver) 34 | else 35 | error('Invalid vars type ' .. type(vars)) 36 | end 37 | end 38 | 39 | return M 40 | -------------------------------------------------------------------------------- /fblualib/mattorch/rockspec/fbmattorch-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbmattorch' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB API to read Matlab files', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'penlight >= 1.3.1', 28 | } 29 | source = { 30 | url = 'https://github.com/facebook/fblualib', 31 | dir = 'fblualib/mattorch', 32 | } 33 | build = { 34 | type = 'command', 35 | build_command = [[ 36 | cmake -E make_directory build && 37 | cd build && 38 | cmake -DROCKS_PREFIX=$(PREFIX) \ 39 | -DROCKS_LUADIR=$(LUADIR) \ 40 | -DROCKS_LIBDIR=$(LIBDIR) \ 41 | .. && 42 | $(MAKE) 43 | ]], 44 | install_command = [[ 45 | cd build && $(MAKE) install 46 | ]], 47 | } 48 | -------------------------------------------------------------------------------- /fblualib/python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | ENABLE_TESTING() 12 | 13 | # Torch messes this up 14 | SET(SAVED_CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) 15 | 16 | SET(CMAKE_MODULE_PATH 17 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake" 18 | "${CMAKE_MODULE_PATH}") 19 | 20 | ADD_DEFINITIONS(-DNO_FOLLY) 21 | ADD_DEFINITIONS(-DNO_THRIFT) 22 | ADD_DEFINITIONS(-DNDEBUG) 23 | 24 | INCLUDE(MultiLevelIncludes) 25 | MLI_SET_DEPTH(1) 26 | 27 | FIND_PACKAGE(Glog REQUIRED) 28 | FIND_PACKAGE(Torch REQUIRED) 29 | 30 | SET(CMAKE_PREFIX_PATH ${Torch_INSTALL_PREFIX}) 31 | FIND_PACKAGE(THPP REQUIRED) 32 | FIND_PACKAGE(Boost REQUIRED COMPONENTS thread) 33 | 34 | FIND_PACKAGE(PythonInterp 2.7) 35 | if(APPLE) 36 | find_program(PYTHON_CONFIG_EXECUTABLE python-config) 37 | if (NOT PYTHON_CONFIG_EXECUTABLE) 38 | message(SEND_ERROR "python-config executable not found, but python is required.") 39 | endif() 40 | # using "python-config --prefix" so that cmake always uses the python that is 41 | # in the user's path, this is a fix for homebrew on Mac: 42 | # https://cmake.org/Bug/view.php?id=14809 43 | execute_process(COMMAND ${PYTHON_CONFIG_EXECUTABLE} --prefix OUTPUT_VARIABLE python_prefix OUTPUT_STRIP_TRAILING_WHITESPACE) 44 | set(PYTHON_INCLUDE_DIR ${python_prefix}/include/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}) 45 | set(PYTHON_LIBRARY ${python_prefix}/lib/libpython${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}${CMAKE_SHARED_LIBRARY_SUFFIX}) 46 | endif() 47 | FIND_PACKAGE(PythonLibs ${PYTHON_VERSION_STRING} REQUIRED) 48 | IF (PYTHONLIBS_VERSION_STRING VERSION_GREATER "3" AND PYTHONLIBS_VERSION_STRING VERSION_GREATER "2") 49 | MESSAGE(FATAL_ERROR "Python Version should be < 3.0, but found python version: ${PYTHONLIBS_VERSION_STRING}") 50 | ENDIF (PYTHONLIBS_VERSION_STRING VERSION_GREATER "3" AND PYTHONLIBS_VERSION_STRING VERSION_GREATER "2") 51 | 52 | FIND_PACKAGE(NumPy REQUIRED) 53 | FIND_LIBRARY(lib_luaT luaT HINTS ${Torch_INSTALL_LIB}) 54 | IF(NOT lib_luaT) 55 | MESSAGE(FATAL_ERROR "libluaT not found") 56 | ENDIF() 57 | 58 | INCLUDE_DIRECTORIES( 59 | ${GLOG_INCLUDE_DIR} 60 | ${THPP_INCLUDE_DIR} 61 | ${PYTHON_INCLUDE_DIRS} 62 | ${NUMPY_INCLUDE_DIRS} 63 | ${Boost_INCLUDE_DIRS} 64 | ) 65 | 66 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") 67 | 68 | SET(src 69 | Debug.cpp 70 | Lib.cpp 71 | LuaToPython.cpp 72 | NumpyArrayAllocator.cpp 73 | PythonToLua.cpp 74 | Ref.cpp 75 | Storage.cpp 76 | Utils.cpp 77 | ) 78 | 79 | ADD_LIBRARY(lua_module MODULE ${src}) 80 | SET_TARGET_PROPERTIES(lua_module PROPERTIES 81 | PREFIX "" 82 | OUTPUT_NAME "lib" 83 | COMPILE_DEFINITIONS "LUAOPEN=luaopen_fb_python_lib") 84 | TARGET_LINK_LIBRARIES(lua_module 85 | dl 86 | luajit 87 | TH 88 | ${lib_luaT} 89 | ${Boost_THREAD_LIBRARIES} 90 | ${GLOG_LIBRARIES} 91 | ${THPP_LIBRARIES} 92 | ${PYTHON_LIBRARIES} 93 | ) 94 | 95 | SET(CMAKE_INSTALL_PREFIX ${SAVED_CMAKE_INSTALL_PREFIX}) 96 | 97 | INSTALL(TARGETS lua_module 98 | DESTINATION "${ROCKS_LIBDIR}/fb/python") 99 | 100 | INSTALL(DIRECTORY "fb" 101 | DESTINATION "${ROCKS_LUADIR}" 102 | FILES_MATCHING 103 | PATTERN "*.lua") 104 | -------------------------------------------------------------------------------- /fblualib/python/Debug.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef NDEBUG 12 | 13 | #include "Debug.h" 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | namespace fblualib { 21 | namespace python { 22 | 23 | namespace { 24 | 25 | class RefMap { 26 | public: 27 | typedef std::unordered_map MapType; 28 | 29 | void add(const void* obj); 30 | void remove(const void* obj); 31 | void check(const void* obj) const; 32 | void checkEqual(const MapType& other) const; 33 | void copyTo(MapType& map); 34 | 35 | private: 36 | std::unordered_map map_; 37 | mutable std::mutex mutex_; 38 | }; 39 | 40 | void RefMap::add(const void* obj) { 41 | CHECK(obj); 42 | std::lock_guard lock(mutex_); 43 | ++map_[obj]; 44 | } 45 | 46 | void RefMap::remove(const void* obj) { 47 | CHECK(obj); 48 | std::lock_guard lock(mutex_); 49 | auto pos = map_.find(obj); 50 | CHECK(pos != map_.end()); 51 | if (--pos->second <= 0) { 52 | CHECK_EQ(pos->second, 0); 53 | map_.erase(pos); 54 | } 55 | } 56 | 57 | void RefMap::check(const void* obj) const { 58 | CHECK(obj); 59 | std::lock_guard lock(mutex_); 60 | auto pos = map_.find(obj); 61 | CHECK(pos != map_.end()); 62 | CHECK_GT(pos->second, 0); 63 | } 64 | 65 | void RefMap::checkEqual(const MapType& other) const { 66 | std::lock_guard lock(mutex_); 67 | CHECK(map_ == other); 68 | } 69 | 70 | void RefMap::copyTo(MapType& map) { 71 | std::lock_guard lock(mutex_); 72 | map = map_; 73 | } 74 | 75 | RefMap* luaRefs = new RefMap; 76 | RefMap* pythonRefs = new RefMap; 77 | 78 | RefMap::MapType* watermarkLuaRefs = new RefMap::MapType; 79 | RefMap::MapType* watermarkPythonRefs = new RefMap::MapType; 80 | 81 | } // namespace 82 | 83 | void debugAddLuaRef(const void* obj) { luaRefs->add(obj); } 84 | void debugDeleteLuaRef(const void* obj) { luaRefs->remove(obj); } 85 | void debugCheckLuaRef(const void* obj) { luaRefs->check(obj); } 86 | void debugCheckNoLuaRefs() { luaRefs->checkEqual(*watermarkLuaRefs); } 87 | 88 | void debugAddPythonRef(const PyObject* obj) { pythonRefs->add(obj); } 89 | void debugDeletePythonRef(const PyObject* obj) { pythonRefs->remove(obj); } 90 | void debugCheckPythonRef(const PyObject* obj) { pythonRefs->check(obj); } 91 | void debugCheckNoPythonRefs() { pythonRefs->checkEqual(*watermarkPythonRefs); } 92 | 93 | void debugSetWatermark() { 94 | luaRefs->copyTo(*watermarkLuaRefs); 95 | pythonRefs->copyTo(*watermarkPythonRefs); 96 | } 97 | 98 | void debugCheckNoRefs() { 99 | debugCheckNoLuaRefs(); 100 | debugCheckNoPythonRefs(); 101 | } 102 | 103 | }} // namespaces 104 | 105 | #endif /* !NDEBUG */ 106 | -------------------------------------------------------------------------------- /fblualib/python/Debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_DEBUG_H_ 12 | #define FBLUA_PYTHON_DEBUG_H_ 13 | 14 | #include 15 | 16 | namespace fblualib { 17 | namespace python { 18 | 19 | #ifndef NDEBUG 20 | 21 | void debugAddLuaRef(const void* obj); 22 | void debugDeleteLuaRef(const void* obj); 23 | void debugCheckLuaRef(const void* obj); 24 | void debugCheckNoLuaRefs(); 25 | 26 | void debugAddPythonRef(const PyObject* obj); 27 | void debugDeletePythonRef(const PyObject* obj); 28 | void debugCheckPythonRef(const PyObject* obj); 29 | void debugCheckNoPythonRefs(); 30 | 31 | void debugSetWatermark(); 32 | void debugCheckNoRefs(); 33 | 34 | #else /* NDEBUG */ 35 | 36 | inline void debugAddLuaRef(const void* obj) { } 37 | inline void debugDeleteLuaRef(const void* obj) { } 38 | inline void debugCheckLuaRef(const void* obj) { } 39 | inline void debugCheckNoLuaRefs() { } 40 | 41 | inline void debugAddPythonRef(const PyObject* obj) { } 42 | inline void debugDeletePythonRef(const PyObject* obj) { } 43 | inline void debugCheckPythonRef(const PyObject* obj) { } 44 | inline void debugCheckNoPythonRefs() { } 45 | 46 | inline void debugSetWatermark() { } 47 | inline void debugCheckNoRefs() { } 48 | 49 | #endif 50 | 51 | }} // namespaces 52 | 53 | #endif /* FBLUA_PYTHON_DEBUG_H_ */ 54 | -------------------------------------------------------------------------------- /fblualib/python/LuaToPython.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_LUATOPYTHON_H_ 12 | #define FBLUA_PYTHON_LUATOPYTHON_H_ 13 | 14 | #include 15 | #include "Utils.h" 16 | 17 | namespace fblualib { 18 | namespace python { 19 | 20 | // Helper class to convert Lua objects to Python objects 21 | class LuaToPythonConverter { 22 | public: 23 | enum : unsigned { 24 | IGNORE_INVALID_TYPES = 1U << 0, 25 | BUILTIN_TYPES_ONLY = 1U << 1, 26 | INTEGRAL_NUMBERS = 1U << 2, 27 | }; 28 | 29 | PyObjectHandle convert(lua_State* L, int index, unsigned flags = 0); 30 | 31 | PyObjectHandle convertDefault(lua_State* L, int index) { 32 | return convert(L, index, 0); 33 | } 34 | PyObjectHandle convertToFloat(lua_State* L, int index); 35 | PyObjectHandle convertToInt(lua_State* L, int index); 36 | PyObjectHandle convertToLong(lua_State* L, int index); 37 | PyObjectHandle convertToBytes(lua_State* L, int index); 38 | PyObjectHandle convertToUnicode(lua_State* L, int index); 39 | PyObjectHandle convertToList(lua_State* L, int index); 40 | PyObjectHandle convertToTuple(lua_State* L, int index); 41 | PyObjectHandle convertToFastSequence(lua_State* L, int index); 42 | PyObjectHandle convertToDict(lua_State* L, int index); 43 | 44 | private: 45 | PyObjectHandle checkRecorded(lua_State* L, int index); 46 | void record(lua_State* L, int index, const PyObjectHandle& obj); 47 | PyObjectHandle convertFromTable(lua_State* L, int index); 48 | PyObjectHandle convertListFromTable(lua_State* L, int index, bool rec=true); 49 | PyObjectHandle convertTupleFromTable(lua_State* L, int index, bool rec=true); 50 | PyObjectHandle convertDictFromTable(lua_State* L, int index, bool rec=true); 51 | 52 | template 53 | PyObjectHandle convertTensor(lua_State* L, thpp::Tensor& tensor, 54 | int numpyType); 55 | 56 | std::unordered_map converted_; 57 | }; 58 | 59 | int initLuaToPython(lua_State* L); 60 | 61 | }} // namespaces 62 | 63 | #endif /* FBLUA_PYTHON_LUATOPYTHON_H_ */ 64 | -------------------------------------------------------------------------------- /fblualib/python/NumpyArrayAllocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #include "NumpyArrayAllocator.h" 12 | 13 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 14 | #include 15 | 16 | #include 17 | 18 | namespace fblualib { 19 | namespace python { 20 | 21 | void* NumpyArrayAllocator::malloc(long size) { 22 | return (*THDefaultAllocator.malloc)(nullptr, size); 23 | } 24 | 25 | void* NumpyArrayAllocator::realloc(void* ptr, long size) { 26 | if (array_ && ptr == PyArray_DATA(array())) { 27 | void* newPtr = this->malloc(size); 28 | memcpy(newPtr, ptr, std::min(size, PyArray_NBYTES(array()))); 29 | // Whee! We're done! 30 | release(); 31 | return newPtr; 32 | } 33 | return (*THDefaultAllocator.realloc)(nullptr, ptr, size); 34 | } 35 | 36 | void NumpyArrayAllocator::free(void* ptr) { 37 | // We're relying on the slightly unsafe (and undocumented) behavior that 38 | // THStorage will only call the "free" method of the allocator once at the 39 | // end of its lifetime. 40 | if (array() && ptr == PyArray_DATA(array())) { 41 | release(); 42 | return; 43 | } 44 | (*THDefaultAllocator.free)(nullptr, ptr); 45 | delete this; 46 | } 47 | 48 | void NumpyArrayAllocator::release() { 49 | if (!array_) { 50 | return; 51 | } 52 | debugDeletePythonRef(array_.get()); 53 | // We may or may not have a Python context, let's be safe. 54 | PythonGuard g; 55 | array_.reset(); 56 | } 57 | 58 | int initNumpyArrayAllocator(lua_State* L) { 59 | initNumpy(L); 60 | return 0; 61 | } 62 | 63 | }} // namespaces 64 | -------------------------------------------------------------------------------- /fblualib/python/NumpyArrayAllocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_NUMPYARRAYALLOCATOR_H_ 12 | #define FBLUA_PYTHON_NUMPYARRAYALLOCATOR_H_ 13 | 14 | #include "Utils.h" 15 | 16 | namespace fblualib { 17 | namespace python { 18 | 19 | // Torch "allocator" that ensures that a given numpy array keeps a reference 20 | // alive until Torch no longer needs the memory. 21 | class NumpyArrayAllocator { 22 | public: 23 | explicit NumpyArrayAllocator(PyObjectHandle a) : array_(std::move(a)) { 24 | debugAddPythonRef(array_.get()); 25 | } 26 | ~NumpyArrayAllocator() { release(); } 27 | 28 | void* malloc(long size); 29 | void* realloc(void* ptr, long size); 30 | void free(void* ptr); 31 | 32 | private: 33 | void release(); 34 | inline PyArrayObject* array() const { 35 | return reinterpret_cast(array_.get()); 36 | } 37 | PyObjectHandle array_; 38 | }; 39 | 40 | int initNumpyArrayAllocator(lua_State* L); 41 | 42 | }} // namespaces 43 | 44 | #endif /* FBLUA_PYTHON_NUMPYARRAYALLOCATOR_H_ */ 45 | -------------------------------------------------------------------------------- /fblualib/python/PythonToLua.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_PYTHONTOLUA_H_ 12 | #define FBLUA_PYTHON_PYTHONTOLUA_H_ 13 | 14 | #include 15 | #include "Utils.h" 16 | 17 | namespace fblualib { 18 | namespace python { 19 | 20 | class PythonToLuaConverter { 21 | public: 22 | enum NoneMode { 23 | NONE_AS_LUA_NIL, 24 | NONE_AS_LUAPY_NONE, 25 | }; 26 | explicit PythonToLuaConverter(NoneMode noneMode): noneMode_(noneMode) {} 27 | 28 | int convert(lua_State* L, const PyObjectHandle& obj); 29 | 30 | private: 31 | int doConvert(lua_State* L, const PyObjectHandle& obj); 32 | // We store all converted lua objects in a Lua list-like table at index 33 | // convertedIdx_. We can't keep them on the stack because the stack is 34 | // limited (and can't be raised above 8000 slots). 35 | int convertedIdx_ = 0; 36 | int convertedCount_ = 0; 37 | // Map from Python object into index in convertedIdx_ 38 | std::unordered_map converted_; 39 | NoneMode noneMode_ = NONE_AS_LUA_NIL; 40 | }; 41 | 42 | int initPythonToLua(lua_State* L); 43 | 44 | }} // namespaces 45 | 46 | #endif /* FBLUA_PYTHON_PYTHONTOLUA_H_ */ 47 | -------------------------------------------------------------------------------- /fblualib/python/Ref.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_REF_H_ 12 | #define FBLUA_PYTHON_REF_H_ 13 | 14 | #include "Utils.h" 15 | 16 | namespace fblualib { 17 | namespace python { 18 | 19 | // Opaque Python reference 20 | struct OpaqueRef { 21 | explicit OpaqueRef(PyObjectHandle o) : obj(std::move(o)) { 22 | if (obj) { 23 | debugAddPythonRef(obj.get()); 24 | } 25 | } 26 | ~OpaqueRef() { 27 | if (obj) { 28 | debugDeletePythonRef(obj.get()); 29 | } 30 | } 31 | PyObjectHandle obj; 32 | }; 33 | 34 | OpaqueRef* checkOpaqueRef(lua_State* L, int index); 35 | OpaqueRef* getOpaqueRef(lua_State* L, int index); 36 | int pushOpaqueRef(lua_State* L, PyObjectHandle obj); 37 | 38 | int initRef(lua_State* L); 39 | 40 | }} // namespaces 41 | 42 | #endif /* FBLUA_PYTHON_REF_H_ */ 43 | -------------------------------------------------------------------------------- /fblualib/python/Storage-inl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_STORAGE_H_ 12 | #error This file may only be included from Storage.h 13 | #endif 14 | 15 | namespace fblualib { 16 | namespace python { 17 | 18 | template 19 | void PythonStorage::define() { 20 | pythonType.ob_type = &PyType_Type; 21 | PyType_Ready(&pythonType); 22 | } 23 | 24 | template 25 | Py_ssize_t PythonStorage::getBuffer(PyObject* selfObj, 26 | Py_ssize_t segment, 27 | void** ptrptr) { 28 | if (segment != 0) { 29 | PyErr_SetString(PyExc_ValueError, "Invalid segment"); 30 | return -1; 31 | } 32 | 33 | *ptrptr = self(selfObj)->storage_.data(); 34 | return self(selfObj)->storage_.size() * sizeof(T); 35 | } 36 | 37 | template 38 | Py_ssize_t PythonStorage::segCount(PyObject* selfObj, Py_ssize_t* lenp) { 39 | if (lenp) { 40 | *lenp = self(selfObj)->storage_.size() * sizeof(T); 41 | } 42 | return 1; 43 | } 44 | 45 | template 46 | void PythonStorage::deallocate(PyObject* selfObj) { 47 | // Call destructor directly, then deallocate memory the Python way. 48 | self(selfObj)->~PythonStorage(); 49 | debugDeletePythonRef(selfObj); 50 | (*pythonType.tp_free)(selfObj); 51 | } 52 | 53 | template 54 | PyBufferProcs PythonStorage::pythonBufferProcs = { 55 | &getBuffer, /*bf_getreadbuffer*/ 56 | &getBuffer, /*bf_getwritebuffer*/ 57 | &segCount, /*bf_getsegcount*/ 58 | nullptr, /*bf_getcharbuffer*/ 59 | }; 60 | 61 | template 62 | PyTypeObject PythonStorage::pythonType = { 63 | PyObject_HEAD_INIT(nullptr) 64 | 0, /*ob_size*/ 65 | "torch.Storage", /* XXX */ /*tp_name*/ 66 | sizeof(PythonStorage), /*tp_basicsize*/ 67 | 0, /*tp_itemsize*/ 68 | deallocate, /*tp_dealloc*/ 69 | 0, /*tp_print*/ 70 | 0, /*tp_getattr*/ 71 | 0, /*tp_setattr*/ 72 | 0, /*tp_compare*/ 73 | 0, /*tp_repr*/ 74 | 0, /*tp_as_number*/ 75 | 0, /*tp_as_sequence*/ 76 | 0, /*tp_as_mapping*/ 77 | 0, /*tp_hash */ 78 | 0, /*tp_call*/ 79 | 0, /*tp_str*/ 80 | 0, /*tp_getattro*/ 81 | 0, /*tp_setattro*/ 82 | &pythonBufferProcs, /*tp_as_buffer*/ 83 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/ 84 | "torch Storage objects", /*tp_doc*/ 85 | }; 86 | 87 | }} // namespaces 88 | -------------------------------------------------------------------------------- /fblualib/python/Storage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #include "Storage.h" 12 | 13 | namespace fblualib { 14 | namespace python { 15 | 16 | int initStorage(lua_State* /*L*/) { 17 | PythonGuard g; 18 | PythonStorage::define(); 19 | PythonStorage::define(); 20 | PythonStorage::define(); 21 | PythonStorage::define(); 22 | PythonStorage::define(); 23 | return 0; 24 | } 25 | 26 | }} // namespaces 27 | -------------------------------------------------------------------------------- /fblualib/python/Storage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_STORAGE_H_ 12 | #define FBLUA_PYTHON_STORAGE_H_ 13 | 14 | #include 15 | #include "Utils.h" 16 | 17 | namespace fblualib { 18 | namespace python { 19 | 20 | // PythonStorage is a Python object that wraps a Storage (holding a reference 21 | // as long as the Python reference count is >0). It also implements the 22 | // buffer interface, but there's currently no use for that, as numpy arrays 23 | // converted using PyArray_FromBuffer don't support strides. 24 | template 25 | class PythonStorage { 26 | public: 27 | PyObject_HEAD 28 | 29 | static PyObjectHandle allocate(lua_State* L, thpp::Storage s) { 30 | // Allocate memory the Python way 31 | PyObject* selfObj = (*pythonType.tp_alloc)(&pythonType, 1); 32 | checkPythonError(selfObj, L, "allocate PythonStorage object"); 33 | debugAddPythonRef(selfObj); 34 | 35 | // Create object with placement new 36 | new (selfObj) PythonStorage(std::move(s)); 37 | return PyObjectHandle(selfObj); 38 | } 39 | 40 | ~PythonStorage() { 41 | #ifndef NDEBUG 42 | if (storage_.data()) { 43 | debugDeleteLuaRef(storage_.data()); 44 | } 45 | #endif 46 | } 47 | 48 | // Define type for Python; for built-in types, this is called from 49 | // initStorage(); 50 | static void define(); 51 | 52 | private: 53 | static PyTypeObject pythonType; 54 | static PyBufferProcs pythonBufferProcs; 55 | 56 | explicit PythonStorage(thpp::Storage s) : storage_(std::move(s)) { 57 | #ifndef NDEBUG 58 | if (storage_.data()) { 59 | debugAddLuaRef(storage_.data()); 60 | } 61 | #endif 62 | } 63 | 64 | // Buffer interface 65 | static Py_ssize_t getBuffer(PyObject* selfObj, Py_ssize_t segment, 66 | void** ptrptr); 67 | static Py_ssize_t segCount(PyObject* selfObj, Py_ssize_t* lenp); 68 | 69 | thpp::Storage storage_; 70 | static void deallocate(PyObject* obj); 71 | 72 | static inline PythonStorage* self(PyObject* obj) { 73 | return reinterpret_cast(obj); 74 | } 75 | }; 76 | 77 | int initStorage(lua_State* L); 78 | 79 | }} // namespaces 80 | 81 | #include "Storage-inl.h" 82 | 83 | #endif /* FBLUA_PYTHON_STORAGE_H_ */ 84 | -------------------------------------------------------------------------------- /fblualib/python/Utils-inl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_PYTHON_UTILS_H_ 12 | #error This file may only be included from Utils.h 13 | #endif 14 | 15 | #include 16 | 17 | namespace fblualib { 18 | namespace python { 19 | 20 | namespace detail { 21 | 22 | inline std::string format() { return ""; } 23 | 24 | inline boost::format& format_helper(boost::format& msg) { return msg; } 25 | 26 | template 27 | boost::format& format_helper(boost::format& msg, H&& val, Tail&&... args) { 28 | return format_helper(msg % std::forward(val), std::forward(args)...); 29 | } 30 | 31 | template 32 | std::string format(std::string fmt, Args&&... args) { 33 | boost::format msg(fmt); 34 | return format_helper(msg, std::forward(args)...).str(); 35 | } 36 | } // namespace detail 37 | 38 | // Raise the current Python error as a Lua error 39 | template 40 | void raisePythonError(lua_State* L, Args&&... args) { 41 | luaL_error(L, "Python error: %s\n%s", 42 | detail::format(std::forward(args)...).c_str(), 43 | formatPythonException().c_str()); 44 | } 45 | 46 | // Check a condition; if false, raise the Python error as a lua error. 47 | template 48 | inline void checkPythonError(Cond&& cond, lua_State* L, Args&&... args) { 49 | if (!cond) { 50 | raisePythonError(L, std::forward(args)...); 51 | } 52 | } 53 | 54 | #ifdef __GNUC__ 55 | #define X_UNUSED __attribute__((__unused__)) 56 | #else 57 | #define X_UNUSED 58 | #endif 59 | 60 | // Yes, static. 61 | // The numpy C API is implemented using macros; PyArray_Foo is expanded 62 | // to (*PyArray_API->foo), and PyArray_API is declared as static in a header 63 | // file. This means it must be initialized (by calling import_array) in 64 | // *every* file where it is used. 65 | namespace detail { 66 | 67 | // The numpy C API is implemented using macros; PyArray_Foo is expanded 68 | // to (*PyArray_API->foo), and PyArray_API is declared as static in a header 69 | // file. This means it must be initialized (by calling import_array) in 70 | // *every* file where it is used. 71 | 72 | X_UNUSED static bool doImportArray() { 73 | // import_array* are macros that return (!!!) 74 | import_array1(false); 75 | return true; 76 | } 77 | 78 | } // namespace detail 79 | 80 | X_UNUSED static int initNumpy(lua_State* L) { 81 | PythonGuard g; 82 | checkPythonError(detail::doImportArray(), L, "import numpy array module"); 83 | return 0; 84 | } 85 | 86 | #undef X_UNUSED 87 | 88 | inline void fixIndex(lua_State* L, int& index) { 89 | if (index < 0) { 90 | index = lua_gettop(L) + index + 1; 91 | } 92 | } 93 | 94 | }} // namespaces 95 | -------------------------------------------------------------------------------- /fblualib/python/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #include "Utils.h" 12 | 13 | namespace fblualib { 14 | namespace python { 15 | 16 | #ifndef NDEBUG 17 | folly::ThreadLocal PythonGuard::count_; 18 | #endif 19 | 20 | // Format the current Python exception as a string. 21 | // Let Python do the work for us; call traceback.format_exception() 22 | std::string formatPythonException() { 23 | if (!PyErr_Occurred()) { 24 | return ""; 25 | } 26 | 27 | // Retrieve Python exception and "normalize" (the docs are unclear but 28 | // they say you should do it :) ) 29 | PyObject* exceptionObj; 30 | PyObject* valueObj; 31 | PyObject* tracebackObj; 32 | PyErr_Fetch(&exceptionObj, &valueObj, &tracebackObj); 33 | DCHECK(exceptionObj); 34 | PyErr_NormalizeException(&exceptionObj, &valueObj, &tracebackObj); 35 | 36 | PyObjectHandle exception(exceptionObj); 37 | PyObjectHandle value(valueObj); 38 | PyObjectHandle traceback(tracebackObj); 39 | 40 | // value and traceback may be null 41 | if (!value) { 42 | value.reset(PyObjectHandle::INCREF, Py_None); 43 | } 44 | if (!traceback) { 45 | traceback.reset(PyObjectHandle::INCREF, Py_None); 46 | } 47 | 48 | PyObjectHandle tbModule(PyImport_ImportModule("traceback")); 49 | if (!tbModule) { 50 | return ""; 51 | } 52 | 53 | PyObject* tbDict = PyModule_GetDict(tbModule.get()); // borrowed 54 | if (!tbDict) { 55 | return ""; 56 | } 57 | 58 | // borrowed 59 | PyObject* formatFunc = PyDict_GetItemString(tbDict, "format_exception"); 60 | if (!formatFunc) { 61 | return ""; 62 | } 63 | 64 | PyObjectHandle formatted(PyObject_CallFunction( 65 | formatFunc, const_cast("OOO"), exception.get(), value.get(), 66 | traceback.get())); 67 | if (!formatted) { 68 | return ""; 69 | } 70 | 71 | // format_exception returns a list of strings that should be concatenated. 72 | // Well then, let's do that. 73 | 74 | if (!PyList_Check(formatted.get())) { 75 | return ""; 76 | } 77 | 78 | std::string out; 79 | for (Py_ssize_t i = 0; i < PyList_GET_SIZE(formatted.get()); ++i) { 80 | PyObject* obj = PyList_GET_ITEM(formatted.get(), i); // borrowed 81 | char* data; 82 | Py_ssize_t len; 83 | if (PyString_AsStringAndSize(obj, &data, &len) == -1) { 84 | return ""; 85 | } 86 | out.append(data, len); 87 | } 88 | 89 | return out; 90 | } 91 | 92 | }} // namespaces 93 | -------------------------------------------------------------------------------- /fblualib/python/cmake/FindGlog.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # GLOG_FOUND 9 | # GLOG_INCLUDE_DIR 10 | # GLOG_LIBRARIES 11 | 12 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 13 | 14 | INCLUDE(FindPackageHandleStandardArgs) 15 | 16 | FIND_LIBRARY(GLOG_LIBRARY glog) 17 | FIND_PATH(GLOG_INCLUDE_DIR "glog/logging.h") 18 | 19 | SET(GLOG_LIBRARIES ${GLOG_LIBRARY}) 20 | 21 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( 22 | Glog 23 | REQUIRED_ARGS GLOG_INCLUDE_DIR GLOG_LIBRARY) 24 | -------------------------------------------------------------------------------- /fblualib/python/cmake/FindNumPy.cmake: -------------------------------------------------------------------------------- 1 | # - Find the NumPy libraries 2 | # This module finds if NumPy is installed, and sets the following variables 3 | # indicating where it is. 4 | # 5 | # TODO: Update to provide the libraries and paths for linking npymath lib. 6 | # 7 | # NUMPY_FOUND - was NumPy found 8 | # NUMPY_VERSION - the version of NumPy found as a string 9 | # NUMPY_VERSION_MAJOR - the major version number of NumPy 10 | # NUMPY_VERSION_MINOR - the minor version number of NumPy 11 | # NUMPY_VERSION_PATCH - the patch version number of NumPy 12 | # NUMPY_VERSION_DECIMAL - e.g. version 1.6.1 is 10601 13 | # NUMPY_INCLUDE_DIRS - path to the NumPy include files 14 | 15 | #============================================================================ 16 | # Copyright 2012 Continuum Analytics, Inc. 17 | # 18 | # MIT License 19 | # 20 | # Permission is hereby granted, free of charge, to any person obtaining 21 | # a copy of this software and associated documentation files 22 | # (the "Software"), to deal in the Software without restriction, including 23 | # without limitation the rights to use, copy, modify, merge, publish, 24 | # distribute, sublicense, and/or sell copies of the Software, and to permit 25 | # persons to whom the Software is furnished to do so, subject to 26 | # the following conditions: 27 | # 28 | # The above copyright notice and this permission notice shall be included 29 | # in all copies or substantial portions of the Software. 30 | # 31 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 32 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 34 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 35 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 36 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 37 | # OTHER DEALINGS IN THE SOFTWARE. 38 | # 39 | #============================================================================ 40 | 41 | # Finding NumPy involves calling the Python interpreter 42 | if(NumPy_FIND_REQUIRED) 43 | find_package(PythonInterp REQUIRED) 44 | else() 45 | find_package(PythonInterp) 46 | endif() 47 | 48 | if(NOT PYTHONINTERP_FOUND) 49 | set(NUMPY_FOUND FALSE) 50 | return() 51 | endif() 52 | 53 | execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" 54 | "import numpy as n; print(n.__version__); print(n.get_include());" 55 | RESULT_VARIABLE _NUMPY_SEARCH_SUCCESS 56 | OUTPUT_VARIABLE _NUMPY_VALUES_OUTPUT 57 | ERROR_VARIABLE _NUMPY_ERROR_VALUE 58 | OUTPUT_STRIP_TRAILING_WHITESPACE) 59 | 60 | if(NOT _NUMPY_SEARCH_SUCCESS MATCHES 0) 61 | if(NumPy_FIND_REQUIRED) 62 | message(FATAL_ERROR 63 | "NumPy import failure:\n${_NUMPY_ERROR_VALUE}") 64 | endif() 65 | set(NUMPY_FOUND FALSE) 66 | return() 67 | endif() 68 | 69 | # Convert the process output into a list 70 | string(REGEX REPLACE ";" "\\\\;" _NUMPY_VALUES ${_NUMPY_VALUES_OUTPUT}) 71 | string(REGEX REPLACE "\n" ";" _NUMPY_VALUES ${_NUMPY_VALUES}) 72 | # Just in case there is unexpected output from the Python command. 73 | list(GET _NUMPY_VALUES -2 NUMPY_VERSION) 74 | list(GET _NUMPY_VALUES -1 NUMPY_INCLUDE_DIRS) 75 | 76 | string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" _VER_CHECK "${NUMPY_VERSION}") 77 | if("${_VER_CHECK}" STREQUAL "") 78 | # The output from Python was unexpected. Raise an error always 79 | # here, because we found NumPy, but it appears to be corrupted somehow. 80 | message(FATAL_ERROR 81 | "Requested version and include path from NumPy, got instead:\n${_NUMPY_VALUES_OUTPUT}\n") 82 | return() 83 | endif() 84 | 85 | # Make sure all directory separators are '/' 86 | string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIRS ${NUMPY_INCLUDE_DIRS}) 87 | 88 | # Get the major and minor version numbers 89 | string(REGEX REPLACE "\\." ";" _NUMPY_VERSION_LIST ${NUMPY_VERSION}) 90 | list(GET _NUMPY_VERSION_LIST 0 NUMPY_VERSION_MAJOR) 91 | list(GET _NUMPY_VERSION_LIST 1 NUMPY_VERSION_MINOR) 92 | list(GET _NUMPY_VERSION_LIST 2 NUMPY_VERSION_PATCH) 93 | string(REGEX MATCH "[0-9]*" NUMPY_VERSION_PATCH ${NUMPY_VERSION_PATCH}) 94 | math(EXPR NUMPY_VERSION_DECIMAL 95 | "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}") 96 | 97 | find_package_message(NUMPY 98 | "Found NumPy: version \"${NUMPY_VERSION}\" ${NUMPY_INCLUDE_DIRS}" 99 | "${NUMPY_INCLUDE_DIRS}${NUMPY_VERSION}") 100 | 101 | set(NUMPY_FOUND TRUE) 102 | 103 | -------------------------------------------------------------------------------- /fblualib/python/cmake/FindTHPP.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | # - Try to find thpp 9 | # This will define 10 | # THPP_FOUND 11 | # THPP_INCLUDE_DIR 12 | # THPP_LIBRARIES 13 | 14 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 15 | 16 | INCLUDE(FindPackageHandleStandardArgs) 17 | 18 | FIND_LIBRARY(THPP_LIBRARY thpp) 19 | FIND_PATH(THPP_INCLUDE_DIR "thpp/Tensor.h") 20 | 21 | SET(THPP_LIBRARIES ${THPP_LIBRARY}) 22 | 23 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Folly 24 | REQUIRED_ARGS THPP_INCLUDE_DIR THPP_LIBRARIES) 25 | -------------------------------------------------------------------------------- /fblualib/python/cmake/MultiLevelIncludes.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | 8 | # Some projects are installed individually as part of a larger tree, but 9 | # include paths always reference the full include path in the tree. This 10 | # module makes it easier to do so. 11 | # 12 | # Suppose you have a source tree fblualib/thrift/submodule, which is built at 13 | # the submodule level (so you have fblualib/thrift/submodule/CMakeLists.txt) 14 | # Files inside submodule include each other (and files from other sibling 15 | # directories) with the full path: 16 | # 17 | # #include 18 | # #include 19 | # #include 20 | # #include 21 | # 22 | # MLI_SET_DEPTH(2) at the root of your CMakeLists.txt would set "../.." 23 | # as the include path (so fblualib is a subdirectory of that), making 24 | # the includes work. Also, it will set MLI_INCLUDE_OUTPUT_DIR and 25 | # MLI_INCLUDE_RELATIVE_OUTPUT_DIR to directories inside the build tree 26 | # where any generators should output header files so they can be found 27 | # via #include. (we recreate the lowest 2 levels of the hierarchy underneath 28 | # ${CMAKE_BINARY_DIR}) 29 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 30 | 31 | FUNCTION(MLI_SET_DEPTH level) 32 | SET(dirs) 33 | SET(dir ${CMAKE_SOURCE_DIR}) 34 | SET(relinc) 35 | FOREACH(i RANGE 1 ${level}) 36 | GET_FILENAME_COMPONENT(bn ${dir} NAME) 37 | GET_FILENAME_COMPONENT(dir ${dir} PATH) 38 | LIST(APPEND dirs ${bn}) 39 | SET(relinc "${relinc}/..") 40 | ENDFOREACH() 41 | LIST(REVERSE dirs) 42 | STRING(REPLACE ";" "/" relpath "${dirs}") 43 | SET(MLI_INCLUDE_OUTPUT_DIR 44 | "${CMAKE_BINARY_DIR}/${relpath}" 45 | PARENT_SCOPE) 46 | SET(MLI_INCLUDE_RELATIVE_OUTPUT_DIR 47 | "${relpath}" 48 | PARENT_SCOPE) 49 | INCLUDE_DIRECTORIES( 50 | "${CMAKE_SOURCE_DIR}/${relinc}" 51 | "${CMAKE_BINARY_DIR}") 52 | ENDFUNCTION() 53 | -------------------------------------------------------------------------------- /fblualib/python/fb/python/init.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local pl = require('pl.import_into')() 11 | local lib = require('fb.python.lib') 12 | 13 | local M = pl.tablex.copy(lib) 14 | 15 | -- Retrieve vars visible at a given level of the stack. 16 | -- Only returns vars that are convertible to Python, and no vars that start 17 | -- with _ (so we don't pollute the Python namespace with our private variables) 18 | local function get_vars(level) 19 | level = level + 1 20 | local vars = {} 21 | 22 | local modules = {} 23 | for _, v in pairs(package.loaded) do 24 | modules[v] = true 25 | end 26 | 27 | local function add(name, value) 28 | local first = name:sub(1, 1) 29 | -- '(': internal variable (from debug.getlocal or debug.getupvalue) 30 | -- '_': likely private, let's not pollute the namespace 31 | if first == '(' or first == '_' or vars[name] then 32 | return 33 | end 34 | local ty = type(value) 35 | if ty == 'function' or ty == 'cdata' then 36 | return 37 | end 38 | -- exclude modules 39 | if modules[value] then 40 | return 41 | end 42 | 43 | vars[name] = value 44 | end 45 | 46 | -- locals 47 | local i = 1 48 | while true do 49 | local name, value = debug.getlocal(level, i) 50 | if not name then 51 | break 52 | end 53 | add(name, value) 54 | i = i + 1 55 | end 56 | 57 | local info = debug.getinfo(level, 'f') 58 | if info.func then 59 | -- upvalues 60 | i = 1 61 | while true do 62 | local name, value = debug.getupvalue(info.func, i) 63 | if not name then 64 | break 65 | end 66 | add(name, value) 67 | i = i + 1 68 | end 69 | -- globals 70 | for name, value in pairs(debug.getfenv(info.func)) do 71 | add(name, value) 72 | end 73 | end 74 | 75 | return vars 76 | end 77 | M.get_vars = get_vars 78 | 79 | -- Execute Python code in context of current stack frame 80 | local function wrap(name) 81 | local function wrapped(code, level) 82 | if not level then 83 | level = 1 84 | end 85 | return lib[name](code, get_vars(level), true) 86 | end 87 | M['l' .. name] = wrapped 88 | end 89 | 90 | wrap('exec') 91 | wrap('eval') 92 | wrap('reval') 93 | 94 | return M 95 | -------------------------------------------------------------------------------- /fblualib/python/rockspec/fbpython-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbpython' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Lua - Python Bridge', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'penlight >= 1.3.1', 28 | } 29 | source = { 30 | url = 'https://github.com/facebook/fblualib', 31 | dir = 'fblualib/python', 32 | } 33 | build = { 34 | type = 'command', 35 | build_command = [[ 36 | cmake -E make_directory build && 37 | cd build && 38 | cmake -DROCKS_PREFIX=$(PREFIX) \ 39 | -DROCKS_LUADIR=$(LUADIR) \ 40 | -DROCKS_LIBDIR=$(LIBDIR) \ 41 | .. && 42 | $(MAKE) 43 | ]], 44 | install_command = [[ 45 | cd build && $(MAKE) install 46 | ]], 47 | } 48 | -------------------------------------------------------------------------------- /fblualib/test/PromiseTest.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Facebook 3 | * @author Tudor Bosman (tudorb@fb.com) 4 | */ 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace fblualib { namespace test { 14 | 15 | LuaStatePtr GL; 16 | 17 | const char kReactorSetUpCode[] = 18 | "local reactor = require('fb.util.reactor')\n" 19 | "\n" 20 | "local R = reactor.Reactor()\n" 21 | "return R, R:get_executor()\n"; 22 | 23 | folly::Executor* setUpReactor() { 24 | auto L = GL.get(); 25 | auto r = luaL_loadstring(L, kReactorSetUpCode); 26 | CHECK_EQ(r, 0); 27 | lua_call(L, 0, 2); 28 | auto executor = static_cast(lua_touserdata(L, -1)); 29 | lua_pop(L, 1); 30 | return executor; 31 | } 32 | 33 | TEST(PromiseTest, SuccessfulFulfillment) { 34 | auto L = GL.get(); 35 | auto executor = setUpReactor(); 36 | // reactor 37 | lua_getfield(L, -1, "awaitv"); 38 | lua_insert(L, -2); 39 | // await reactor 40 | auto promise = Promise::create(L); 41 | // await reactor future 42 | folly::via(executor) 43 | .then( 44 | [&promise] () { 45 | auto L = loopingState().L; 46 | luaPush(L, 42); 47 | luaPush(L, 100); 48 | promise.setValue(L, 2); 49 | }); 50 | int r = lua_pcall(L, 2, 2, 0); 51 | EXPECT_EQ(0, r); 52 | if (r != 0) { 53 | LOG(ERROR) << luaGetChecked(L, -1); 54 | } 55 | EXPECT_EQ(42, luaGetChecked(L, -2)); 56 | EXPECT_EQ(100, luaGetChecked(L, -1)); 57 | } 58 | 59 | TEST(PromiseTest, ErrorFulfillment) { 60 | auto L = GL.get(); 61 | auto executor = setUpReactor(); 62 | // reactor 63 | lua_getfield(L, -1, "awaitv"); 64 | lua_insert(L, -2); 65 | // await reactor 66 | auto promise = Promise::create(L); 67 | // await reactor promise 68 | folly::via(executor) 69 | .then( 70 | [&promise] () { 71 | auto L = loopingState().L; 72 | promise.setErrorFrom(L, "hello"); 73 | }); 74 | int r = lua_pcall(L, 2, 0, 0); 75 | EXPECT_EQ(LUA_ERRRUN, r); 76 | EXPECT_TRUE(luaGetChecked(L, -1).find("hello") != 77 | folly::StringPiece::npos); 78 | } 79 | 80 | }} // namespaces 81 | 82 | using namespace fblualib; 83 | using namespace fblualib::test; 84 | 85 | int main(int argc, char *argv[]) { 86 | testing::InitGoogleTest(&argc, argv); 87 | gflags::ParseCommandLineFlags(&argc, &argv, true); 88 | 89 | initLuaEmbedding(); 90 | GL = luaNewState(); 91 | auto L = GL.get(); 92 | luaL_openlibs(L); 93 | 94 | initFuture(L); 95 | 96 | return RUN_ALL_TESTS(); 97 | } 98 | -------------------------------------------------------------------------------- /fblualib/thrift/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | ENABLE_TESTING() 12 | 13 | # Torch messes this up 14 | SET(SAVED_CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) 15 | 16 | SET(CMAKE_MODULE_PATH 17 | "${CMAKE_CURRENT_SOURCE_DIR}/../cmake" 18 | "${CMAKE_MODULE_PATH}") 19 | 20 | INCLUDE(MultiLevelIncludes) 21 | MLI_SET_DEPTH(2) 22 | 23 | FIND_PACKAGE(Folly REQUIRED) 24 | FIND_PACKAGE(Glog REQUIRED) 25 | FIND_PACKAGE(Thrift REQUIRED) 26 | FIND_PACKAGE(Torch REQUIRED) 27 | FIND_PACKAGE(THPP) 28 | FIND_PACKAGE(FBLuaLib REQUIRED) 29 | 30 | INCLUDE_DIRECTORIES( 31 | ${FOLLY_INCLUDE_DIR} 32 | ${GLOG_INCLUDE_DIR} 33 | ${THRIFT_INCLUDE_DIR} 34 | ${THPP_INCLUDE_DIR} 35 | ${FBLUALIB_INCLUDE_DIR} 36 | ) 37 | 38 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14") 39 | 40 | SET(base_src 41 | ChunkedCompression.cpp 42 | Encoding.cpp 43 | LuaObject.cpp 44 | ) 45 | ADD_THRIFT2(base_src "if/ChunkedCompression.thrift") 46 | ADD_THRIFT2(base_src "if/LuaObject.thrift") 47 | 48 | SET(base_h 49 | ChunkedCompression.h 50 | Encoding.h 51 | LuaObject.h 52 | LuaObject-inl.h 53 | ) 54 | 55 | ADD_LIBRARY(fblualib_thrift SHARED ${base_src}) 56 | TARGET_LINK_LIBRARIES(fblualib_thrift 57 | ${FOLLY_LIBRARIES} ${GLOG_LIBRARIES} ${THRIFT_LIBRARIES} 58 | ${THPP_LIBRARIES}) 59 | 60 | SET(module_src 61 | Serialization.cpp 62 | LuaSerialization.cpp 63 | ) 64 | 65 | ADD_LIBRARY(lua_module MODULE ${module_src}) 66 | SET_TARGET_PROPERTIES(lua_module PROPERTIES 67 | PREFIX "" 68 | OUTPUT_NAME "lib" 69 | COMPILE_DEFINITIONS "LUAOPEN=luaopen_fb_thrift_lib") 70 | TARGET_LINK_LIBRARIES(lua_module 71 | fblualib_thrift luaT ${FBLUALIB_LIBRARIES}) 72 | 73 | SET(CMAKE_INSTALL_PREFIX ${SAVED_CMAKE_INSTALL_PREFIX}) 74 | 75 | INSTALL(TARGETS fblualib_thrift 76 | LIBRARY DESTINATION ${Torch_INSTALL_LIB}) 77 | 78 | INSTALL(FILES ${base_h} 79 | DESTINATION "${Torch_INSTALL_INCLUDE}/include/${MLI_INCLUDE_RELATIVE_OUTPUT_DIR}") 80 | INSTALL_THRIFT2_HEADERS("if" "${Torch_INSTALL_INCLUDE}/include") 81 | 82 | INSTALL(TARGETS lua_module 83 | DESTINATION "${ROCKS_LIBDIR}/fb/thrift") 84 | 85 | INSTALL(DIRECTORY "fb" 86 | DESTINATION "${ROCKS_LUADIR}" 87 | FILES_MATCHING 88 | PATTERN "*.lua") 89 | -------------------------------------------------------------------------------- /fblualib/thrift/ChunkedCompression.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Facebook 3 | * @author Tudor Bosman (tudorb@fb.com) 4 | */ 5 | 6 | #include 7 | 8 | namespace fblualib { namespace thrift { 9 | 10 | std::unique_ptr compressChunked( 11 | folly::io::Codec* codec, 12 | const folly::IOBuf* uncompressed, 13 | uint64_t chunkLength, 14 | ChunkList& chunks) { 15 | folly::io::Cursor cursor(uncompressed); 16 | folly::IOBufQueue compressed(folly::IOBufQueue::cacheChainLength()); 17 | uint64_t compressedLength = 0; 18 | 19 | for (;;) { 20 | std::unique_ptr uncompressedChunk; 21 | size_t n = cursor.cloneAtMost(uncompressedChunk, chunkLength); 22 | if (n == 0) { 23 | break; 24 | } 25 | 26 | Chunk chunk; 27 | chunk.uncompressedLength = n; 28 | compressed.append(codec->compress(uncompressedChunk.get())); 29 | 30 | // Don't walk the IOBuf chain twice, let IOBufQueue::append do the 31 | // job, we'll compute the current length as the difference of 32 | // (queue new length) - (queue old length) 33 | auto newLength = compressed.chainLength(); 34 | chunk.compressedLength = newLength - compressedLength; 35 | compressedLength = newLength; 36 | 37 | chunks.chunks.push_back(std::move(chunk)); 38 | } 39 | 40 | return compressed.move(); 41 | } 42 | 43 | std::unique_ptr uncompressChunked( 44 | folly::io::Codec* codec, 45 | const folly::IOBuf* compressed, 46 | const ChunkList& chunks) { 47 | folly::io::Cursor cursor(compressed); 48 | folly::IOBufQueue uncompressed(folly::IOBufQueue::cacheChainLength()); 49 | uint64_t uncompressedLength = 0; 50 | 51 | for (auto& chunk : chunks.chunks) { 52 | std::unique_ptr compressedChunk; 53 | size_t n = cursor.cloneAtMost(compressedChunk, chunk.compressedLength); 54 | if (n != chunk.compressedLength) { 55 | throw std::runtime_error("underflow"); 56 | } 57 | 58 | uncompressed.append(codec->uncompress(compressedChunk.get(), 59 | chunk.uncompressedLength)); 60 | 61 | // Don't walk the IOBuf chain twice, let IOBufQueue::append do the 62 | // job, we'll compute the current length as the difference of 63 | // (queue new length) - (queue old length) 64 | auto newLength = uncompressed.chainLength(); 65 | if (newLength - uncompressedLength != chunk.uncompressedLength) { 66 | throw std::runtime_error("decompression error"); 67 | } 68 | uncompressedLength = newLength; 69 | } 70 | 71 | return uncompressed.move(); 72 | } 73 | 74 | }} // namespaces 75 | -------------------------------------------------------------------------------- /fblualib/thrift/ChunkedCompression.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUALIB_THRIFT_CHUNKEDCOMPRESSION_H_ 12 | #define FBLUALIB_THRIFT_CHUNKEDCOMPRESSION_H_ 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | namespace fblualib { namespace thrift { 23 | 24 | // Some compression implementations (such as LZ4 and Snappy) have a maximum size 25 | // of a compressed object (the limit is 1.9GiB for LZ4 and 4GiB for Snappy). 26 | // 27 | // If we want to compress objects larger than the limit, we use a 28 | // chunked scheme where we break down the object into chunks smaller 29 | // than the limit and compress them independently. 30 | // 31 | // Note that the chunks are compressed as separate compressed objects, 32 | // not as part of the same stream; we wouldn't need to use chunking if 33 | // the compression implementation supported streams of unlimited length. 34 | 35 | std::unique_ptr compressChunked( 36 | folly::io::Codec* codec, 37 | const folly::IOBuf* uncompressed, 38 | uint64_t chunkLength, 39 | ChunkList& chunks); 40 | 41 | std::unique_ptr uncompressChunked( 42 | folly::io::Codec* codec, 43 | const folly::IOBuf* compressed, 44 | const ChunkList& chunks); 45 | 46 | }} // namespaces 47 | 48 | #endif /* FBLUALIB_THRIFT_CHUNKEDCOMPRESSION_H_ */ 49 | -------------------------------------------------------------------------------- /fblualib/thrift/Encoding.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #ifndef FBLUA_THRIFT_ENCODING_H_ 12 | #define FBLUA_THRIFT_ENCODING_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace fblualib { namespace thrift { 19 | 20 | // void writer(std::unique_ptr data); 21 | constexpr int kAnyVersion = std::numeric_limits::max(); 22 | 23 | template 24 | void encode(const LuaObject& input, folly::io::CodecType codec, 25 | LuaVersionInfo versionInfo, Writer&& writer, 26 | int maxVersion = kAnyVersion, 27 | uint64_t chunkLength = std::numeric_limits::max()); 28 | 29 | struct DecodedObject { 30 | LuaObject output; 31 | LuaVersionInfo luaVersionInfo; 32 | }; 33 | 34 | // std::unique_ptr reader(size_t n); 35 | template 36 | DecodedObject decode(Reader&& reader); 37 | 38 | class FILEWriter { 39 | public: 40 | explicit FILEWriter(FILE* fp) : fp_(fp) { } 41 | 42 | void operator()(std::unique_ptr data); 43 | private: 44 | FILE* fp_; 45 | }; 46 | 47 | class FILEReader { 48 | public: 49 | explicit FILEReader(FILE* fp) : fp_(fp) { } 50 | 51 | std::unique_ptr operator()(size_t n); 52 | private: 53 | FILE* fp_; 54 | }; 55 | 56 | class StringWriter { 57 | public: 58 | folly::ByteRange finish(); 59 | void operator()(std::unique_ptr data); 60 | 61 | private: 62 | folly::IOBuf buf_; 63 | }; 64 | 65 | class StringReader { 66 | public: 67 | // Note that str must outlive the decoded object, as the IOBufs inside 68 | // DecodedObject will end up pointing to str (but will be marked as shared). 69 | explicit StringReader(folly::ByteRange* str) : str_(str) { } 70 | 71 | std::unique_ptr operator()(size_t n); 72 | 73 | private: 74 | folly::ByteRange* str_; 75 | }; 76 | 77 | }} // namespaces 78 | 79 | #endif /* FBLUA_THRIFT_ENCODING_H_ */ 80 | -------------------------------------------------------------------------------- /fblualib/thrift/LuaObject-inl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2014 Facebook 3 | * @author Tudor Bosman (tudorb@fb.com) 4 | */ 5 | 6 | #ifndef FBLUA_THRIFT_LUAOBJECT_H_ 7 | #error This file may only be included from fblualib/thrift/LuaObject.h 8 | #endif 9 | 10 | namespace fblualib { namespace thrift { 11 | 12 | namespace detail { 13 | LuaVersionInfo cppVersionInfo(); 14 | } // namespace detail 15 | 16 | template 17 | void cppEncode(const LuaObject& input, folly::io::CodecType codec, 18 | Writer&& writer) { 19 | return encode(input, codec, detail::cppVersionInfo(), 20 | std::forward(writer)); 21 | } 22 | 23 | template 24 | LuaObject cppDecode(Reader&& reader) { 25 | return decode(std::forward(reader)).output; 26 | } 27 | 28 | }} // namespaces 29 | -------------------------------------------------------------------------------- /fblualib/thrift/LuaSerialization.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | #include "Encoding.h" 14 | #include "Serialization.h" 15 | #include 16 | 17 | using namespace fblualib; 18 | using namespace fblualib::thrift; 19 | using folly::io::CodecType; 20 | 21 | namespace { 22 | 23 | struct CodecInfo { 24 | const char* name; 25 | CodecType type; 26 | }; 27 | 28 | CodecInfo gCodecs[] = { 29 | {"NONE", CodecType::NO_COMPRESSION}, 30 | {"LZ4", CodecType::LZ4}, 31 | {"SNAPPY", CodecType::SNAPPY}, 32 | {"ZLIB", CodecType::ZLIB}, 33 | {"LZMA2", CodecType::LZMA2}, 34 | }; 35 | 36 | constexpr size_t kCodecCount = sizeof(gCodecs) / sizeof(gCodecs[0]); 37 | 38 | LuaVersionInfo getVersion(lua_State* L) { 39 | int origTop = lua_gettop(L); 40 | lua_getglobal(L, "jit"); 41 | if (lua_isnil(L, -1)) { 42 | luaL_error(L, "Cannot find global \"jit\", cannot determine version"); 43 | } 44 | int jitIdx = lua_gettop(L); 45 | 46 | // Just to make sure, look at jit.version, see if it starts with LuaJIT 47 | lua_getfield(L, jitIdx, "version"); 48 | auto ver = luaGetStringChecked(L, -1); 49 | if (!ver.startsWith("LuaJIT")) { 50 | luaL_error(L, "Invalid jit.version, expecting LuaJIT: %*s", 51 | ver.size(), ver.data()); 52 | } 53 | 54 | LuaVersionInfo info; 55 | info.interpreterVersion = ver.str(); 56 | 57 | // LuaJIT bytecode is compatible between the same . 58 | // version_num is * 10000 + * 100 + 59 | lua_getfield(L, jitIdx, "version_num"); 60 | long verNum = lua_tointeger(L, -1); 61 | if (verNum < 2 * 100 * 100) { 62 | luaL_error(L, "Invalid LuaJIT version, expected >= 20000: %ld", verNum); 63 | } 64 | 65 | info.bytecodeVersion = folly::sformat("LuaJIT:{:04d}", verNum / 100); 66 | 67 | lua_settop(L, origTop); 68 | return info; 69 | } 70 | 71 | int serializeToString(lua_State* L) { 72 | auto codecType = 73 | (lua_type(L, 2) != LUA_TNIL && lua_type(L, 2) != LUA_TNONE ? 74 | static_cast(luaL_checkinteger(L, 2)) : 75 | CodecType::NO_COMPRESSION); 76 | auto luaChunkSize = luaGetNumber(L, 4); 77 | uint64_t chunkSize = 78 | luaChunkSize ? *luaChunkSize : std::numeric_limits::max(); 79 | 80 | auto obj = Serializer::toThrift(L, 1, 3); 81 | 82 | StringWriter writer; 83 | encode(obj, codecType, getVersion(L), writer, kAnyVersion, chunkSize); 84 | 85 | auto str = folly::StringPiece(writer.finish()); 86 | lua_pushlstring(L, str.data(), str.size()); 87 | return 1; 88 | } 89 | 90 | int serializeToFile(lua_State* L) { 91 | auto codecType = 92 | (lua_type(L, 3) != LUA_TNIL && lua_type(L, 3) != LUA_TNONE ? 93 | static_cast(luaL_checkinteger(L, 3)) : 94 | CodecType::NO_COMPRESSION); 95 | auto luaChunkSize = luaGetNumber(L, 5); 96 | uint64_t chunkSize = 97 | luaChunkSize ? *luaChunkSize : std::numeric_limits::max(); 98 | 99 | auto fp = luaDecodeFILE(L, 2); 100 | 101 | auto obj = Serializer::toThrift(L, 1, 4); 102 | 103 | FILEWriter writer(fp); 104 | encode(obj, codecType, getVersion(L), writer, kAnyVersion, chunkSize); 105 | 106 | return 0; 107 | } 108 | 109 | int doDeserialize(lua_State* L, DecodedObject&& decodedObject, int envIdx) { 110 | auto version = getVersion(L); 111 | 112 | Deserializer::Options options; 113 | // Check for bytecode version compatibility 114 | auto& decodedBytecodeVersion = decodedObject.luaVersionInfo.bytecodeVersion; 115 | if (decodedBytecodeVersion.empty() || 116 | decodedBytecodeVersion != version.bytecodeVersion) { 117 | options.allowBytecode = false; 118 | } 119 | 120 | return Deserializer::fromThrift(L, std::move(decodedObject.output), 121 | envIdx, std::move(options)); 122 | } 123 | 124 | int deserializeFromString(lua_State* L) { 125 | folly::ByteRange br(luaGetStringChecked(L, 1)); 126 | StringReader reader(&br); 127 | return doDeserialize(L, decode(reader), 2); 128 | } 129 | 130 | int deserializeFromFile(lua_State* L) { 131 | auto fp = luaDecodeFILE(L, 1); 132 | FILEReader reader(fp); 133 | return doDeserialize(L, decode(reader), 2); 134 | } 135 | 136 | int setCallbacks(lua_State* L) { 137 | // Set serialization and deserialization callbacks for special objects 138 | luaL_checktype(L, 1, LUA_TFUNCTION); 139 | luaL_checktype(L, 2, LUA_TFUNCTION); 140 | setSpecialSerializationCallback(L, 1); 141 | setSpecialDeserializationCallback(L, 2); 142 | return 0; 143 | } 144 | 145 | const struct luaL_reg gFuncs[] = { 146 | {"_to_string", serializeToString}, 147 | {"_to_file", serializeToFile}, 148 | {"_from_string", deserializeFromString}, 149 | {"_from_file", deserializeFromFile}, 150 | {"_set_callbacks", setCallbacks}, 151 | {nullptr, nullptr}, // sentinel 152 | }; 153 | 154 | } // namespace 155 | 156 | extern "C" int LUAOPEN(lua_State* L) { 157 | lua_newtable(L); 158 | luaL_register(L, nullptr, gFuncs); 159 | 160 | // Create "codec" table 161 | lua_newtable(L); 162 | 163 | for (size_t i = 0; i < kCodecCount; ++i) { 164 | auto codecType = gCodecs[i].type; 165 | try { 166 | auto codec = folly::io::getCodec(codecType); 167 | } catch (const std::invalid_argument& e) { 168 | continue; 169 | } 170 | lua_pushinteger(L, static_cast(codecType)); 171 | lua_setfield(L, -2, gCodecs[i].name); 172 | } 173 | lua_setfield(L, -2, "codec"); 174 | 175 | return 1; 176 | } 177 | -------------------------------------------------------------------------------- /fblualib/thrift/README.md: -------------------------------------------------------------------------------- 1 | # fb-thrift: Thrift serialization for Lua objects 2 | 3 | This module implements Thrift serialization for arbitrary Lua objects with 4 | optional compression. Scalars, tables, functions with upvalues (serializing 5 | bytecode), and torch Tensors are supported. The module supports serializing 6 | arbitrary object graphs (with cycles), and the graph is restored properly on 7 | deserialization. 8 | 9 | There is additional support for Torch objects (created with `torch.class`) and 10 | [Penlight](http://stevedonovan.github.io/Penlight/api/index.html) objects 11 | (`pl.class`); see below. 12 | 13 | ## Lua interface 14 | ```lua 15 | local thrift = require('fb.thrift') 16 | 17 | local obj = { foo = 2 } -- arbitrary Lua object 18 | 19 | -- Serialization 20 | 21 | -- to Lua string 22 | local str = thrift.to_string(obj) 23 | 24 | -- to open io.file object 25 | local f = io.open('/tmp/foo', 'wb') 26 | thrift.to_file(obj, f) 27 | 28 | -- Deserialization 29 | 30 | -- from Lua string 31 | local obj = thrift.from_string(str) 32 | 33 | -- from open io.file object 34 | local f = io.open('/tmp/foo') 35 | local obj = thrift.from_file(obj) 36 | ``` 37 | 38 | `to_file` writes to the file at the current position of the file pointer, 39 | and advances the file pointer past the serialized data. `from_file` reads 40 | from the current file pointer and advances the file pointer past the serialized 41 | data (that is, the format is self-delimiting, and you can serialize multiple 42 | objects to the same file without any special framing). 43 | 44 | Serialization functions (`to_file' and `to_string') accept an additional 45 | argument that indicates the codec to use when compressing the data, if any. 46 | Valid values are in the `thrift.codec` table: `NONE` (no compression, default), 47 | `LZ4`, `SNAPPY`, `ZLIB`, `LZMA2` (but some might not be available if the 48 | corresponding library wasn't installed on your system when 49 | [folly](https://github.com/facebook/folly) was built). 50 | 51 | ## OOP support 52 | 53 | There is additional support for Object-Oriented Programming using 54 | `torch.class`, Penlight's `pl.class`, and adding other OOP schemes is easy. 55 | 56 | For Torch objects, the class is correctly identified at serialization time and 57 | restored at deserialization time. 58 | 59 | For Penlight objects, you must explicitly add all classes that you want 60 | to be able to serialize with `thrift.add_penlight_class(cls, name)`, where 61 | `cls` is the class to serialize, and `name` is a globally unique name; 62 | when deserializing, you must call `add_penlight_class` with the same 63 | class -- name mapping. You may add multiple Penlight classes at once 64 | by using `add_penlight_classes`; see the documentation in the Lua file for 65 | details. 66 | 67 | For both Torch and Penlight classes, if the class has methods named 68 | `_thrift_serialize` and `_thrift_deserialize`, these methods will be called 69 | at serialization and deserialization time, respectively, as follows: 70 | 71 | At serialization time, before an object of that class is serialized, we call 72 | `obj:_thrift_serialize()`. This method must either return a table (that will 73 | be serialized *instead of* `obj`) or `nil` (which means we'll serialize `obj`; 74 | this gives you an opportunity to blow away temporary fields that shouldn't be 75 | serialized.) 76 | 77 | At deserialization time, we call `_thrift_deserialize(obj)` which must mutate 78 | obj *in place*. `obj` is a table (not yet blessed as a Torch or Penlight 79 | class), and `_thrift_deserialize` must set fields appropriately so that it can 80 | be blessed and produce a valid object; we'll then bless the object by making 81 | it of the correct class. 82 | 83 | Adding support for other OOP schemes is easy; see the documentation for 84 | `add_metatable` in the Lua file. 85 | 86 | ## C++ interface 87 | There is limited support for writing and reading Lua-serialized objects from 88 | C++, without calling into Lua. Currently, only scalars and tensors are 89 | supported. See `LuaObject.h` for details (you should be able to 90 | include it as ``) 91 | -------------------------------------------------------------------------------- /fblualib/thrift/if/ChunkedCompression.thrift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | 10 | namespace cpp2 fblualib.thrift 11 | 12 | struct Chunk { 13 | 1: i64 compressedLength, 14 | 2: i64 uncompressedLength, 15 | } 16 | 17 | struct ChunkList { 18 | 1: list chunks; 19 | } 20 | -------------------------------------------------------------------------------- /fblualib/thrift/if/LuaObject.thrift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014, Facebook, Inc. 3 | // All rights reserved. 4 | // 5 | // This source code is licensed under the BSD-style license found in the 6 | // LICENSE file in the root directory of this source tree. An additional grant 7 | // of patent rights can be found in the PATENTS file in the same directory. 8 | // 9 | // 10 | // Thrift serialization for arbitrary Lua objects. 11 | // 12 | // We support primitive types (nil, number, boolean, string) and 13 | // reference types (string, table, function, userdata). The only 14 | // supported userdata is torch tensors. Note that string may be either 15 | // a primitive type or a reference type, depending on whether it's interned 16 | // or not. 17 | // 18 | // We store all objects of reference types in LuaObject.refs. LuaPrimitive 19 | // represents an object of a primitive type, or the index of a reference 20 | // in LuaObject.refs. 21 | // 22 | // We try to make this useful from C/C++ by separating table elements 23 | // according to their keys: list-like (consecutive integers starting at 1; note 24 | // that the indexes in LuaTable.listKeys start at 0!), other integral keys, 25 | // string keys, boolean keys, and "other". So a list would only have 26 | // listKeys set, a string-keyed dictionary would only have stringKeys set, etc. 27 | // Of course, an arbitrary Lua table may have more than one such field set, 28 | // but that's unusual. 29 | // 30 | // We store functions (as bytecode) and also serialize function upvalues. 31 | // Bytecode is not guaranteed to be compatible across Lua versions, and 32 | // we check for this when deserializing. (For LuaJIT, versions with the same 33 | // major and minor version number are bytecode-compatible; that is, LuaJIT 34 | // 2.0.2 is compatible (forwards and backwards) with LuaJIT 2.0.x, but not 35 | // LuaJIT 2.1.x or LuaJIT 3.x.y) 36 | 37 | namespace cpp2 fblualib.thrift 38 | 39 | include "thpp/if/Tensor.thrift" 40 | include "fblualib/thrift/if/ChunkedCompression.thrift" 41 | 42 | typedef binary (cpp2.type = "folly::IOBuf") IOBuf 43 | 44 | struct LuaPrimitiveObject { 45 | 1: bool isNil, 46 | 2: optional double doubleVal, 47 | 3: optional bool boolVal, 48 | 4: optional binary stringVal, 49 | 5: optional i64 refVal, 50 | } 51 | 52 | struct LuaPrimitiveObjectKV { 53 | 1: LuaPrimitiveObject key, 54 | 2: LuaPrimitiveObject value, 55 | } 56 | 57 | struct LuaTable { 58 | 1: optional list listKeys, 59 | 2: optional map (cpp.template = 'std::unordered_map') stringKeys, 60 | 3: optional map (cpp.template = 'std::unordered_map') intKeys, 61 | 4: optional LuaPrimitiveObject trueKey, 62 | 5: optional LuaPrimitiveObject falseKey, 63 | 6: optional list otherKeys, 64 | 7: optional LuaPrimitiveObject specialKey, 65 | 8: optional LuaPrimitiveObject specialValue, 66 | 9: optional LuaPrimitiveObject metatable, 67 | } 68 | 69 | struct LuaFunction { 70 | 1: IOBuf bytecode, 71 | 2: list upvalues, 72 | } 73 | 74 | struct LuaExternalEnvLocation { 75 | 1: required LuaPrimitiveObject env, // may not be reference 76 | 2: required LuaPrimitiveObject key, // may not be reference 77 | } 78 | 79 | struct LuaUserData { 80 | 1: required string key, 81 | 2: required IOBuf value, 82 | } 83 | 84 | struct LuaRefObject { 85 | 1: optional binary stringVal, 86 | 2: optional LuaTable tableVal, 87 | 3: optional LuaFunction functionVal, 88 | 4: optional Tensor.ThriftTensor tensorVal, 89 | 5: optional Tensor.ThriftStorage storageVal, 90 | 6: optional LuaExternalEnvLocation envLocation, 91 | 7: optional LuaUserData customUserDataVal, 92 | 8: optional i64 memRefVal, 93 | } 94 | 95 | typedef list LuaRefList 96 | 97 | // A Lua object. 98 | struct LuaObject { 99 | 1: LuaPrimitiveObject value, 100 | 2: LuaRefList refs, 101 | } 102 | 103 | struct LuaVersionInfo { 104 | // Encodings with different bytecodeVersion can't deserialize 105 | // functions (bytecode) 106 | 1: string bytecodeVersion, 107 | 2: string interpreterVersion, 108 | } 109 | 110 | struct ThriftHeader { 111 | // 0 = initial version 112 | // 1 = support for metatables, specials 113 | // 2 = support for chunked encoding 114 | // 3 = support for external environments 115 | // 4 = support for custom userdata 116 | 1: i32 version, 117 | 2: i32 codec, 118 | 3: i64 uncompressedLength, 119 | 4: i64 compressedLength, 120 | 5: LuaVersionInfo luaVersionInfo, 121 | 6: optional ChunkedCompression.ChunkList chunks, 122 | } 123 | -------------------------------------------------------------------------------- /fblualib/thrift/rockspec/fbthrift-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbthrift' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Thrift Lua Serialization', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'penlight >= 1.3.1', 28 | } 29 | source = { 30 | url = 'https://github.com/facebook/fblualib', 31 | dir = 'fblualib/thrift', 32 | } 33 | build = { 34 | type = 'command', 35 | build_command = [[ 36 | cmake -E make_directory build && 37 | cd build && 38 | cmake -DROCKS_PREFIX=$(PREFIX) \ 39 | -DROCKS_LUADIR=$(LUADIR) \ 40 | -DROCKS_LIBDIR=$(LIBDIR) \ 41 | .. && 42 | $(MAKE) 43 | ]], 44 | install_command = [[ 45 | cd build && $(MAKE) install 46 | ]], 47 | } 48 | -------------------------------------------------------------------------------- /fblualib/thrift/test/lua_object_test.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | require('fb.luaunit') 11 | 12 | local torch = require('torch') 13 | local thrift = require('fb.thrift') 14 | local lib = require('fb.thrift.test.lib') 15 | 16 | local function check_nil() 17 | assertEquals(nil, thrift.from_string(lib.write_nil())) 18 | lib.read_nil(thrift.to_string(nil)) 19 | end 20 | 21 | local function check_bool(val) 22 | assertEquals(val, thrift.from_string(lib.write_bool(val))) 23 | assertEquals(val, lib.read_bool(thrift.to_string(val))) 24 | end 25 | 26 | local function check_double(val) 27 | assertEquals(val, thrift.from_string(lib.write_double(val))) 28 | assertEquals(val, lib.read_double(thrift.to_string(val))) 29 | end 30 | 31 | local function check_string(val) 32 | assertEquals(val, thrift.from_string(lib.write_string(val))) 33 | assertEquals(val, lib.read_string(thrift.to_string(val))) 34 | end 35 | 36 | local function assertTensorEquals(t1, t2) 37 | assertEquals(t1:dim(), t2:dim()) 38 | 39 | for i = 1, t1:dim() do 40 | assertEquals(t1:size(i), t2:size(i)) 41 | end 42 | 43 | t1 = t1:contiguous() 44 | t2 = t2:contiguous() 45 | 46 | t1:resize(t1:nElement()) 47 | t2:resize(t2:nElement()) 48 | 49 | for i = 1, t1:nElement() do 50 | assertEquals(t1[i], t2[i]) 51 | end 52 | end 53 | 54 | local function check_tensor(val) 55 | assertTensorEquals(val, thrift.from_string(lib.write_tensor(val))) 56 | assertTensorEquals(val, lib.read_tensor(thrift.to_string(val))) 57 | end 58 | 59 | function testLuaObject() 60 | check_nil() 61 | check_bool(false) 62 | check_bool(true) 63 | check_double(42) 64 | check_double(42.5) 65 | check_string('') 66 | check_string('hello world') 67 | local t = torch.DoubleTensor():rand(5, 10) 68 | check_tensor(t) 69 | end 70 | 71 | function testTableIteration() 72 | local t = { 73 | [1] = 10, 74 | [2] = 20, 75 | [3] = 30, 76 | [true] = 40, 77 | [false] = 50, 78 | hello = 60, 79 | world = 70, 80 | [100] = 80, 81 | [200] = 90, 82 | } 83 | lib.check_table_iteration(thrift.to_string(t)) 84 | end 85 | 86 | LuaUnit:main() 87 | -------------------------------------------------------------------------------- /fblualib/torch/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | ENABLE_TESTING() 12 | 13 | SET(CMAKE_MODULE_PATH 14 | "${CMAKE_CURRENT_SOURCE_DIR}/../cmake" 15 | "${CMAKE_MODULE_PATH}") 16 | 17 | FIND_PACKAGE(Torch REQUIRED) 18 | 19 | INCLUDE(MultiLevelIncludes) 20 | MLI_SET_DEPTH(2) 21 | 22 | FIND_PACKAGE(Folly REQUIRED) 23 | FIND_PACKAGE(Torch REQUIRED) 24 | 25 | INCLUDE_DIRECTORIES( 26 | ${FOLLY_INCLUDE_DIR} 27 | ) 28 | 29 | INCLUDE_DIRECTORIES(${LUA_INCDIR}) 30 | 31 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") 32 | 33 | SET(src 34 | AsyncRNG.cpp 35 | ) 36 | 37 | SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 38 | 39 | ADD_LIBRARY(async_rng MODULE ${src}) 40 | set_target_properties(async_rng 41 | PROPERTIES PREFIX "") 42 | 43 | TARGET_LINK_LIBRARIES(async_rng ${FOLLY_LIBRARIES} fblualib) 44 | 45 | install(TARGETS async_rng LIBRARY 46 | DESTINATION "${ROCKS_LIBDIR}/fb/torch") 47 | -------------------------------------------------------------------------------- /fblualib/torch/rockspec/fbtorch-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbtorch' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Basic Lua Utilities', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | source = { 27 | url = 'https://github.com/facebook/fblualib', 28 | dir = 'fblualib/torch', 29 | } 30 | build = { 31 | type = 'command', 32 | build_command = [[ 33 | cmake -E make_directory build && 34 | cd build && 35 | cmake -DROCKS_PREFIX=$(PREFIX) \ 36 | -DROCKS_LUADIR=$(LUADIR) \ 37 | -DROCKS_LIBDIR=$(LIBDIR) \ 38 | -DLUA_INCDIR="$(LUA_INCDIR)" \ 39 | .. && 40 | $(MAKE) 41 | ]], 42 | install_command = [[ 43 | cd build && $(MAKE) install 44 | ]], 45 | } 46 | -------------------------------------------------------------------------------- /fblualib/trepl/README.md: -------------------------------------------------------------------------------- 1 | # fb-trepl: Read-Eval-Print loop 2 | 3 | This module implements a Read-Eval-Print loop with command line editing and 4 | pretty colorized output. It is based heavily on 5 | [torch/trepl](https://github.com/torch/trepl). 6 | 7 | Colorized output is on if the output is to a terminal and off otherwise; 8 | behavior can be changed by the value of the `TORCH_COLOR` environment variable: 9 | * `always` enables colorized output always (even when output is not to a 10 | terminal) 11 | * `never` disable colorized output altogether 12 | 13 | Usage: to run the default REPL: 14 | 15 | ```lua 16 | local repl = require('fb.repl') 17 | repl.repl() 18 | ``` 19 | 20 | (from the command line, try `luajit -e "require('fb.repl').repl()"`) 21 | 22 | You may create additional REPLs that do not share state with the main REPL 23 | (if any) -- useful if your program needs to accept arbitrary Lua input 24 | and evaluate it: 25 | 26 | ```lua 27 | local loop = repl.make_repl() 28 | loop() 29 | ``` 30 | -------------------------------------------------------------------------------- /fblualib/trepl/rockspec/fbtrepl-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbtrepl' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Basic Lua Utilities', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'penlight >= 1.3.1', 28 | 'fbutil >= 0.1', 29 | 'fbeditline >= 0.1', 30 | } 31 | source = { 32 | url = 'https://github.com/facebook/fblualib', 33 | dir = 'fblualib/trepl', 34 | } 35 | build = { 36 | type = 'builtin', 37 | modules = { 38 | ['fb.trepl.init'] = 'fb/trepl/init.lua', 39 | }, 40 | } 41 | -------------------------------------------------------------------------------- /fblualib/util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Facebook, Inc. 2 | # All rights reserved. 3 | # 4 | # This source code is licensed under the BSD-style license found in the 5 | # LICENSE file in the root directory of this source tree. An additional grant 6 | # of patent rights can be found in the PATENTS file in the same directory. 7 | # 8 | 9 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7 FATAL_ERROR) 10 | 11 | ENABLE_TESTING() 12 | 13 | SET(CMAKE_MODULE_PATH 14 | "${CMAKE_CURRENT_SOURCE_DIR}/../cmake" 15 | "${CMAKE_MODULE_PATH}") 16 | 17 | INCLUDE(MultiLevelIncludes) 18 | MLI_SET_DEPTH(2) 19 | 20 | FIND_PACKAGE(Folly REQUIRED) 21 | FIND_PACKAGE(Torch REQUIRED) 22 | FIND_PACKAGE(FBLuaLib REQUIRED) 23 | 24 | INCLUDE_DIRECTORIES( 25 | ${FOLLY_INCLUDE_DIR} 26 | ) 27 | 28 | INCLUDE_DIRECTORIES(${LUA_INCDIR}) 29 | 30 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14") 31 | 32 | SET(src 33 | Util.cpp 34 | Reactor.cpp 35 | ) 36 | 37 | SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 38 | 39 | ADD_LIBRARY(fbutil MODULE ${src}) 40 | TARGET_LINK_LIBRARIES(fbutil ${FOLLY_LIBRARIES}) 41 | TARGET_LINK_LIBRARIES(fbutil ${FBLUALIB_LIBRARIES}) 42 | 43 | INSTALL(TARGETS fbutil LIBRARY DESTINATION ${ROCKS_LIBDIR}) 44 | 45 | INSTALL( 46 | DIRECTORY "fb" 47 | DESTINATION "${ROCKS_LUADIR}" 48 | FILES_MATCHING 49 | PATTERN "*.lua") 50 | 51 | INSTALL( 52 | DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/fb" 53 | DESTINATION "${ROCKS_LUADIR}" 54 | FILES_MATCHING 55 | PATTERN "*.lua") 56 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/_config.lua.in: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | return { 11 | clib = '@clib@', 12 | } 13 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/_promise_registry.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | -- Internal module for the use of fblualib/Promise.h 11 | 12 | local future = require('fb.util.future') 13 | local M = {} 14 | 15 | local id = 0 -- 2**53 values ought to be enough for everybody 16 | 17 | local promises = {} 18 | 19 | function M.create(...) 20 | id = id + 1 21 | local p = {future.Promise(), ...} 22 | promises[id] = p 23 | return p[1]:future(), id 24 | end 25 | 26 | local function dispatch(k, method, ...) 27 | local p = promises[k][1] 28 | p[method](p, ...) 29 | promises[k] = nil 30 | end 31 | 32 | function M.set_value(k, ...) 33 | return dispatch(k, 'set_value', ...) 34 | end 35 | 36 | function M.set_error(k, e) 37 | return dispatch(k, 'set_error', e) 38 | end 39 | 40 | return M 41 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/data.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local M = {} 11 | 12 | -- deepcopy routine that assumes the presence of a 'clone' method in user 13 | -- data should be used to deeply copy. This matches the behavior of Torch 14 | -- tensors. 15 | function M.deepcopy(x) 16 | local typename = type(x) 17 | if typename == "userdata" then 18 | return x:clone() 19 | end 20 | if typename == "table" then 21 | local retval = { } 22 | for k,v in pairs(x) do 23 | retval[M.deepcopy(k)] = M.deepcopy(v) 24 | end 25 | return retval 26 | end 27 | return x 28 | end 29 | 30 | return M 31 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/dbg.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local pl = require('pl.import_into')() 11 | local M = {} 12 | 13 | -- Facility for conditional debug output. Controlled via the 'DBG' environment 14 | -- variable, which is a comma-separated list of name= pairs. 15 | -- Typical use might be: 16 | -- 17 | -- local dbg = require 'dbg' 18 | -- local dprint = dbg.new('myModuleName') 19 | -- 20 | -- ... 21 | -- dprint('Initializing...\n") -- Prints if DBG=myModuleName= 22 | -- dprint(2, 'Reticulating splines: ', numSplines) 23 | 24 | function M.new(mod) 25 | return function(level, ...) 26 | if M.dbgSettings[mod] and M.dbgSettings[mod] >= level then 27 | print(...) 28 | end 29 | end 30 | end 31 | 32 | local function parse_debug_str(str) 33 | local retval = { } 34 | if not str then 35 | return retval 36 | end 37 | local chunks = pl.utils.split(str, ',') 38 | for i, chunk in ipairs(chunks) do 39 | local pair = pl.utils.split(chunk, '=') 40 | if #pair == 1 then 41 | -- If the user didn't specify a level, turn on all statements 42 | -- for this module. 43 | retval[pair[1]] = 1e8 44 | elseif #pair == 2 then 45 | retval[pair[1]] = tonumber(pair[2]) 46 | else 47 | error("bad DBG segment: " .. chunk) 48 | end 49 | end 50 | return retval 51 | end 52 | 53 | local success, settings = pcall(function() 54 | return parse_debug_str(os.getenv('DBG')) 55 | end) 56 | 57 | if success then 58 | M.dbgSettings = settings 59 | else 60 | print("failed to parse DBG env var", os.getenv('DBG')) 61 | end 62 | -- Use the 'dbgmeta' module to debug dbg. 63 | local dprint = M.new('fb.util.dbg') 64 | 65 | dprint(1, "dbg settings", M.dbgSettings) 66 | 67 | return M 68 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/file.lua: -------------------------------------------------------------------------------- 1 | -- nothing in lua's io library can truncate, so roll our own assuming 2 | -- unix. 3 | local ffi = require 'ffi' 4 | local M = {} 5 | 6 | -- man 2 truncate 7 | ffi.cdef[[ 8 | int truncate(const char* path, size_t len); 9 | int unlink(const char* pathname); 10 | ]] 11 | 12 | M.truncate = ffi.C.truncate 13 | M.unlink = ffi.C.unlink 14 | 15 | return M 16 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/logging.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | -- Logging facility, using google-glog for logging. 11 | -- 12 | -- Similar to Python's logging. Usage: 13 | -- 14 | -- local logging = require('fb.util.logging') 15 | -- 16 | -- logging.info('Hello ', 42) -- logs 'Hello 42' at INFO severity 17 | -- logging.log(logging.INFO, 'Hello ', 42) -- or specify explicitly 18 | -- 19 | -- Also available are warn (to log with WARNING severity), error 20 | -- (to log with ERROR severity), and fatal (to log with FATAL severity, 21 | -- which will cause an immediate crash by calling abort()!) 22 | -- 23 | -- There are also functions with the 'f' suffix (logf, infof, warnf, errorf, 24 | -- fatalf) that process the first (or second, in the case of logf) argument 25 | -- as a string.format string, and the remaining arguments as arguments to 26 | -- the format string: 27 | -- 28 | -- logging.infof('Hello %.2f!', 42) -- logs 'Hello 42.00!' at INFO severity 29 | -- logging.logf(logging.INFO, 'Hello %.2f!', 42) -- same 30 | 31 | local ffi = require('ffi') 32 | local util = require('fb.util') 33 | local clib = util._clib 34 | 35 | local M = {} 36 | 37 | local INFO = 0 38 | local WARNING = 1 39 | local ERROR = 2 40 | -- Note that FATAL will crash your program by calling abort()! 41 | local FATAL = 3 42 | M.INFO = INFO 43 | M.WARNING = WARNING 44 | M.ERROR = ERROR 45 | M.FATAL = FATAL 46 | 47 | ffi.cdef([=[ 48 | void luaInitLogging(const char* argv0); 49 | void luaLog(int severity, const char* file, int line, const char* msg); 50 | ]=]) 51 | 52 | local function _logm(depth, severity, msg) 53 | -- 0 = getinfo 54 | -- 1 = _log 55 | local info = debug.getinfo(depth + 1, 'nlS') 56 | 57 | local file = 'LUA_UNKNOWN' 58 | if info.source then 59 | local source_type = string.sub(info.source, 1, 1) 60 | local source = string.sub(info.source, 2) 61 | if source_type == '@' then -- file 62 | file = source 63 | elseif source_type == '=' then -- literal 64 | file = 'LUA_' .. string.gsub(source, '[^%w_%.%-]', '_') 65 | else 66 | file = 'LUA_EVAL' 67 | end 68 | end 69 | 70 | local line = info.currentline 71 | if not line or line <= 0 then 72 | line = 1 73 | end 74 | clib.luaLog(severity, file, line, msg) 75 | end 76 | 77 | local function _log(depth, severity, ...) 78 | local n = select('#', ...) 79 | local strings = {} 80 | for i = 1, n do 81 | table.insert(strings, tostring(select(i, ...))) 82 | end 83 | _logm(depth + 1, severity, table.concat(strings)) 84 | end 85 | 86 | local function _logf(depth, severity, fmt, ...) 87 | _logm(depth + 1, severity, string.format(fmt, ...)) 88 | end 89 | 90 | local function log(severity, ...) 91 | return _log(1, severity, ...) 92 | end 93 | M.log = log 94 | 95 | local function logf(severity, ...) 96 | return _logf(1, severity, ...) 97 | end 98 | M.logf = logf 99 | 100 | local function info(...) 101 | return _log(1, INFO, ...) 102 | end 103 | M.info = info 104 | 105 | local function infof(...) 106 | return _logf(1, INFO, ...) 107 | end 108 | M.infof = infof 109 | 110 | local function warn(...) 111 | return _log(1, WARNING, ...) 112 | end 113 | M.warn = warn 114 | M.warning = warn 115 | 116 | local function warnf(...) 117 | return _logf(1, WARNING, ...) 118 | end 119 | M.warnf = warnf 120 | M.warningf = warnf 121 | 122 | local function _error(...) 123 | return _log(1, ERROR, ...) 124 | end 125 | M.error = _error 126 | 127 | local function errorf(...) 128 | return _logf(1, ERROR, ...) 129 | end 130 | M.errorf = errorf 131 | 132 | local function fatal(...) 133 | return _log(1, FATAL, ...) 134 | end 135 | M.fatal = fatal 136 | 137 | local function fatalf(...) 138 | return _logf(1, FATAL, ...) 139 | end 140 | M.fatalf = fatalf 141 | 142 | -- Initialize logging library 143 | clib.luaInitLogging('') 144 | 145 | return M 146 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/multi_level.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | -- utilities to deal with multi-level tables (tables of tables) 11 | -- 12 | -- set(table, k1, k2, ..., kn, val) is the same as 13 | -- table[k1][k2]...[kn] = val 14 | -- except that intermediate tables are created automatically 15 | -- 16 | -- del(table, k1, k2, ..., kn) is the same as 17 | -- table[k1][k2]...[kn] = nil 18 | -- except that intermediate tables that have become empty are deleted 19 | -- 20 | -- get(table, k1, k2, ..., kn) is the same as 21 | -- table[k1][k2]...[kn] 22 | -- except that it returns nil if any intermediate table is missing 23 | -- (rather than throwing an error) 24 | local function del(t, ...) 25 | local args = {...} 26 | local stack = { } 27 | local lt 28 | local nlt = t 29 | for i = 1, #args do 30 | lt = nlt 31 | if type(lt) ~= 'table' then 32 | return false 33 | end 34 | stack[i] = lt 35 | nlt = lt[args[i]] 36 | if nlt == nil then 37 | return false 38 | end 39 | end 40 | lt[args[#args]] = nil 41 | 42 | local i = #args 43 | while i >= 1 and not next(stack[i]) do 44 | i = i - 1 45 | end 46 | if i >= 1 then 47 | stack[i][args[i]] = nil 48 | end 49 | return true 50 | end 51 | 52 | local function _set(overwrite, t, ...) 53 | local args = {...} 54 | local lt = t 55 | for i = 1, #args - 2 do 56 | local nlt = lt[args[i]] 57 | if not nlt then 58 | nlt = { } 59 | lt[args[i]] = nlt 60 | end 61 | lt = nlt 62 | end 63 | if not overwrite then 64 | local prev = lt[args[#args - 1]] 65 | if prev ~= nil then 66 | return prev 67 | end 68 | end 69 | local v = args[#args] 70 | lt[args[#args - 1]] = v 71 | return v 72 | end 73 | 74 | local function set(t, ...) 75 | _set(true, t, ...) 76 | end 77 | 78 | local function setdefault(t, ...) 79 | return _set(false, t, ...) 80 | end 81 | 82 | local function get(t, ...) 83 | local args = {...} 84 | local lt 85 | local nlt = t 86 | for i = 1, #args do 87 | lt = nlt 88 | if type(lt) ~= 'table' then 89 | return nil 90 | end 91 | nlt = lt[args[i]] 92 | if nlt == nil then 93 | return false 94 | end 95 | end 96 | return nlt 97 | end 98 | 99 | return { 100 | get = get, 101 | set = set, 102 | setdefault = setdefault, 103 | del = del, 104 | } 105 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/reactor.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | -- Reactor pattern, wrapping a C++ EventBase 11 | -- 12 | -- - loop() 13 | -- Will block until some progress has been made (at least one callback 14 | -- was called); returns the number of callbacks that have run. 15 | -- 16 | -- - loop_nb() 17 | -- Non-blocking version of loop(); returns immediately (and returns 0) 18 | -- if no callbacks are runnable. Note that delayed callbacks are not 19 | -- considered runnable until their timer has expired. 20 | -- 21 | -- - run(cb, ...) 22 | -- Add a callback to be called the next time loop() is invoked. Returns a 23 | -- unique id that can be passed to remove_callback() or lookup_callback() 24 | -- 25 | -- - run_after_delay(seconds, cb, ...) 26 | -- Add a callback to be called when loop() is invoked, but no earlier than 27 | -- the given number of seconds. Returns a unique id that can be passed 28 | -- to remove_callback() or lookup_callback() 29 | -- 30 | -- - remove_callback(id) 31 | -- Removes the callback; returns the callback state prior to removing. 32 | -- 33 | -- - lookup_callback(id) 34 | -- Returns the callback state as a string (one of 'runnable', 'delayed') 35 | -- or nil if the callback is not found 36 | -- 37 | -- - await(f) 38 | -- Wait for future f to be completed. Calls loop() underneath. Note that f 39 | -- must be completed as a result of some callbacks scheduled to run in this 40 | -- Reactor, or else you'll block forever. 41 | -- 42 | -- Reactor is reentrant; if some callbacks call loop() (directly or via 43 | -- await()), everything works as intended. 44 | -- 45 | -- More interestingly, callbacks can be scheduled from C++ code (either 46 | -- embedding Lua, or from a C++ module); get_executor() will return a 47 | -- lightuserdata corresponding to a folly::Executor* that C++ code can use 48 | -- for this purpose. 49 | 50 | local util = require('fb.util') 51 | local pl = require('pl.import_into')() 52 | local cmod = require('fb.util.reactor_c') 53 | 54 | local state_names = { 55 | [cmod.RUNNABLE] = 'runnable', 56 | [cmod.DELAYED] = 'delayed', 57 | } 58 | 59 | local M = {} 60 | 61 | local Reactor = pl.class() 62 | 63 | function Reactor:_init() 64 | self._reactor = cmod:new() 65 | end 66 | 67 | local function make_closure(cb, ...) 68 | local args = util.pack_n(...) 69 | return function() cb(util.unpack_n(args)) end 70 | end 71 | 72 | function Reactor:run(cb, ...) 73 | return self._reactor:add_callback(make_closure(cb, ...)) 74 | end 75 | 76 | function Reactor:run_after_delay(seconds, cb, ...) 77 | return self._reactor:add_callback_delayed(seconds, make_closure(cb, ...)) 78 | end 79 | 80 | function Reactor:remove_callback(id) 81 | return state_names[self._reactor:remove_callback(id)] 82 | end 83 | 84 | function Reactor:lookup_callback(id) 85 | return state_names[self._reactor:lookup_callback(id)] 86 | end 87 | 88 | function Reactor:loop() 89 | return self._reactor:loop(true) 90 | end 91 | 92 | function Reactor:loop_nb() 93 | return self._reactor:loop(false) 94 | end 95 | 96 | function Reactor:await(future) 97 | local done = false 98 | future:on_completion(function() done = true end) 99 | while not done do 100 | self:loop() 101 | end 102 | return future 103 | end 104 | 105 | function Reactor:awaitv(future) 106 | return self:await(future):value() 107 | end 108 | 109 | function Reactor:get_executor() 110 | return self._reactor:get_executor() 111 | end 112 | 113 | function Reactor:get_event_base() 114 | return self._reactor:get_event_base() 115 | end 116 | 117 | M.Reactor = Reactor 118 | 119 | return M 120 | -------------------------------------------------------------------------------- /fblualib/util/fb/util/stats.lua: -------------------------------------------------------------------------------- 1 | -- Copyright 2004-present Facebook. All Rights Reserved. 2 | 3 | local Stats = { 4 | DEFAULT_DECAY_FACTOR = 2 5 | } 6 | 7 | function Stats.new(name, decay_factor) 8 | local self = { 9 | name = name or nil, 10 | last_value = 0, 11 | avg = 0, 12 | stddevsqr = 0, 13 | n = 0, 14 | min = math.huge, 15 | max = -math.huge, 16 | total = 0, 17 | decay_factor = decay_factor or Stats.DEFAULT_DECAY_FACTOR, 18 | davg = 0, 19 | decaying_stddevsqr = 0, 20 | } 21 | setmetatable(self, {__index = Stats}) 22 | return self 23 | end 24 | 25 | function Stats:add(value) 26 | self.last_value = value 27 | self.total = self.total + value 28 | -- see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance 29 | self.n = self.n + 1; 30 | local delta = value - self.avg 31 | self.avg = self.avg + delta / self.n 32 | local md = 1 / self.decay_factor 33 | if (self.n == 1) then 34 | self.davg = value 35 | end 36 | 37 | self.davg = (md * self.davg + (1 - md) * value); 38 | 39 | -- This expression uses the new value of mean 40 | self.stddevsqr = self.stddevsqr + delta * (value - self.avg); 41 | self.decaying_stddevsqr = 42 | self.decaying_stddevsqr + delta * (value - self.davg) 43 | 44 | self.max = math.max(self.max, value); 45 | self.min = math.min(self.min, value); 46 | end 47 | 48 | function Stats:get_variance() 49 | if self.n > 1 then 50 | return math.sqrt(self.stddevsqr / (self.n - 1)); 51 | else 52 | return 0 53 | end 54 | end 55 | 56 | function Stats:get_dvariance() 57 | if self.n > 1 then 58 | return math.sqrt(self.decaying_stddevsqr / (self.n - 1)); 59 | else 60 | return 0 61 | end 62 | end 63 | 64 | function Stats:reset() 65 | self.last_value = 0 66 | self.avg = 0 67 | self.stddevsqr = 0 68 | self.n = 0 69 | self.min = math.huge 70 | self.max = -math.huge 71 | self.total = 0 72 | self.davg = 0 73 | self.decaying_stddevsqr = 0 74 | end 75 | 76 | return Stats 77 | -------------------------------------------------------------------------------- /fblualib/util/rockspec/fbutil-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | package = 'fbutil' 11 | version = '0.1-1' 12 | source = { 13 | url = 'https://github.com/facebook/fblualib', 14 | } 15 | description = { 16 | summary = 'FB Basic Lua Utilities', 17 | detailed = [[ 18 | XXX 19 | ]], 20 | homepage = 'https://github.com/facebook/fblualib', 21 | license = 'BSD', 22 | } 23 | supported_platforms = { 24 | 'unix', 25 | } 26 | dependencies = { 27 | 'penlight >= 1.3.1', 28 | } 29 | source = { 30 | url = 'https://github.com/facebook/fblualib', 31 | dir = 'fblualib/util', 32 | } 33 | build = { 34 | type = 'command', 35 | build_command = [[ 36 | cmake -E make_directory build && 37 | cd build && 38 | cmake -DROCKS_PREFIX=$(PREFIX) \ 39 | -DROCKS_LUADIR=$(LUADIR) \ 40 | -DROCKS_LIBDIR=$(LIBDIR) \ 41 | -DLUA_INCDIR="$(LUA_INCDIR)" \ 42 | .. && 43 | $(MAKE) 44 | ]], 45 | install_command = [[ 46 | cd build && $(MAKE) install 47 | ]], 48 | } 49 | -------------------------------------------------------------------------------- /fblualib/util/test/digraph_test.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local digraph = require('fb.util.digraph') 11 | local pl = require('pl.import_into')() 12 | 13 | require('fb.luaunit') 14 | 15 | local function sorted(t) 16 | return pl.List(t):sort() 17 | end 18 | 19 | TestDigraph = {} 20 | 21 | function TestDigraph:setUp() 22 | self.G = digraph.Digraph() 23 | for i = 1, 10 do 24 | self.G:add_vertex(i) 25 | end 26 | for i = 1, 9 do 27 | self.G:add_edge(i + 1, i, i * 10) 28 | end 29 | end 30 | 31 | function TestDigraph:testBasic() 32 | local G = self.G 33 | 34 | assertEquals(10, #G) 35 | for i = 1, 10 do 36 | assertTrue(G:has_vertex(i)) 37 | end 38 | assertFalse(G:has_vertex(11)) 39 | 40 | assertEquals(10, G:vertex_count()) 41 | assertEquals(9, G:edge_count()) 42 | assertEquals({10}, G:sources()) 43 | assertEquals({1}, G:sinks()) 44 | assertTrue(pl.tablex.compare_no_order( 45 | {[4] = 40}, 46 | G:out_edges(5))) 47 | assertTrue(pl.tablex.compare_no_order( 48 | {[5] = 40}, 49 | G:in_edges(4))) 50 | 51 | G:add_edge(1, 3) 52 | assertEquals({}, G:sinks()) 53 | 54 | assertEquals({2}, G:predecessors(1)) 55 | assertEquals({3}, sorted(G:successors(1))) 56 | assertEquals({1, 4}, sorted(G:predecessors(3))) 57 | assertEquals({2}, G:successors(3)) 58 | end 59 | 60 | function TestDigraph:testRemoveVertex() 61 | local G = self.G 62 | 63 | for i = 10, 1, -1 do 64 | assertTrue(G:has_vertex(i)) 65 | if i > 1 then 66 | assertEquals(G:get_edge(i, i - 1), (i - 1) * 10) 67 | end 68 | 69 | G:remove_vertex(i) 70 | assertFalse(G:has_vertex(i)) 71 | 72 | if i > 1 then 73 | assertEquals(G:get_edge(i, i - 1), nil) 74 | end 75 | end 76 | end 77 | 78 | function TestDigraph:testForEach() 79 | local G = self.G 80 | local seen = {} 81 | 82 | G:for_each(function(v) seen[v] = (seen[v] or 0) + 1 end) 83 | assertEquals(pl.Set(seen), pl.Set({1, 1, 1, 1, 1, 1, 1, 1, 1, 1})) 84 | end 85 | 86 | function TestDigraph:testTopoSort1() 87 | local G = self.G 88 | 89 | assertEquals({10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, G:topo_sort()); 90 | assertEquals({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, G:reverse_topo_sort()); 91 | 92 | G:add_edge(1, 5); 93 | 94 | assertError(G.topo_sort, G); 95 | assertError(G.reverse_topo_sort, G); 96 | end 97 | 98 | function TestDigraph:testClone() 99 | local G = self.G:clone( 100 | function(v) return string.format('v%d', v) end, 101 | function(e) return string.format('e%d', e) end) 102 | 103 | assertEquals(10, #G) 104 | assertEquals(10, G:vertex_count()) 105 | assertEquals(9, G:edge_count()) 106 | assertEquals({'v10'}, G:sources()) 107 | assertEquals({'v1'}, G:sinks()) 108 | assertTrue(pl.tablex.compare_no_order( 109 | {v4 = 'e40'}, 110 | G:out_edges('v5'))) 111 | assertTrue(pl.tablex.compare_no_order( 112 | {v5 = 'e40'}, 113 | G:in_edges('v4'))) 114 | G:add_edge('v1', 'v3') 115 | assertEquals({}, G:sinks()) 116 | 117 | assertEquals({'v2'}, G:predecessors('v1')) 118 | assertEquals({'v3'}, sorted(G:successors('v1'))) 119 | assertEquals({'v1', 'v4'}, sorted(G:predecessors('v3'))) 120 | assertEquals({'v2'}, G:successors('v3')) 121 | end 122 | 123 | function testCross() 124 | local G1 = digraph.Digraph() 125 | 126 | local cross_from = {} 127 | for i = 1, 10 do 128 | table.insert(cross_from, i + 10) 129 | G1:add_vertex(i) 130 | G1:add_vertex(i + 10) 131 | G1:add_edge(i, i + 10) 132 | end 133 | assertEquals(20, #G1) 134 | 135 | local cross_to = {} 136 | 137 | local G2 = digraph.Digraph() 138 | for i = 101, 110 do 139 | table.insert(cross_to, i) 140 | G2:add_vertex(i) 141 | G2:add_vertex(i + 10) 142 | G2:add_edge(i, i + 10) 143 | end 144 | assertEquals(20, #G2) 145 | 146 | G1:cross(G2) 147 | 148 | assertEquals(40, #G1) 149 | assertEquals(0, #G2) 150 | 151 | for i = 1, 10 do 152 | assertEquals({}, G1:predecessors(i)) 153 | assertEquals({i + 10}, G1:successors(i)) 154 | assertEquals({i}, G1:predecessors(i + 10)) 155 | assertEquals(cross_to, sorted(G1:successors(i + 10))) 156 | assertEquals(cross_from, sorted(G1:predecessors(i + 100))) 157 | assertEquals({i + 110}, G1:successors(i + 100)) 158 | assertEquals({i + 100}, G1:predecessors(i + 110)) 159 | assertEquals({}, G1:successors(i + 110)) 160 | end 161 | end 162 | 163 | function testForEachCycle() 164 | local G = digraph.Digraph() 165 | 166 | G:add_vertex(1) 167 | G:add_vertex(2) 168 | G:add_edge(1, 2) 169 | G:add_edge(2, 1) 170 | 171 | local seen = {} 172 | G:for_each(function(v) seen[v] = (seen[v] or 0) + 1 end) 173 | 174 | assertEquals(pl.Set(seen), pl.Set({1, 1})) 175 | end 176 | 177 | LuaUnit:main() 178 | -------------------------------------------------------------------------------- /fblualib/util/test/file_test.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | require 'fb.luaunit' 11 | 12 | local file = require 'fb.util.file' 13 | 14 | function testTrunc() 15 | local filename = os.tmpname() 16 | local f = io.open(filename, 'w') 17 | for i = 1, 1024 do 18 | f:write("w") 19 | end 20 | f:close() 21 | 22 | file.truncate(filename, 0) 23 | f = io.open(filename, 'r') 24 | local size = f:seek('end') 25 | f:close() 26 | assertEquals(size, 0) 27 | 28 | file.unlink(filename) 29 | end 30 | 31 | testTrunc() 32 | LuaUnit:main() 33 | -------------------------------------------------------------------------------- /fblualib/util/test/find_test.lua: -------------------------------------------------------------------------------- 1 | -- Copyright 2004-present Facebook. All Rights Reserved. 2 | 3 | require 'fb.luaunit' 4 | 5 | local torch = require('torch') 6 | local find = require('fb.util').find 7 | 8 | function testfind1d() 9 | local dim1 = math.random(10,1000) 10 | local a = torch.randn(dim1) 11 | local id = find(a:ge(0)) 12 | local b = a:index(1,id) 13 | local s1 = b:sum() 14 | local ap = (a+torch.abs(a))/2 15 | local s2 = ap:sum() 16 | assertEquals( s1, s2 ) 17 | end 18 | 19 | function testfind2d() 20 | local dim1 = math.random(10,1000) 21 | local dim2 = math.random(10,1000) 22 | local a = torch.randn(dim1,dim2) 23 | local rowid = math.random(1,dim1) 24 | local colid = math.random(1,dim2) 25 | 26 | local idc1 = find(a:ge(0)[{{},{colid}}]:squeeze()) 27 | local idc2 = find(a[{{},{colid}}]:ge(0):squeeze()) 28 | 29 | local idr1 = find(a:ge(0)[{{rowid},{}}]:squeeze()) 30 | local idr2 = find(a[{{rowid},{}}]:ge(0):squeeze()) 31 | 32 | 33 | local col = a[{{},{colid}}]:squeeze():clone() 34 | local row = a[{{rowid},{}}]:squeeze():clone() 35 | 36 | local poscol1 = col:index(1, idc1) 37 | local poscol2 = col:index(1, idc2) 38 | local posrow1 = row:index(1, idr1) 39 | local posrow2 = row:index(1, idr2) 40 | local poscolsum1 = poscol1:sum() 41 | local poscolsum2 = poscol2:sum() 42 | local posrowsum1 = posrow1:sum() 43 | local posrowsum2 = posrow2:sum() 44 | 45 | local colp = (col + torch.abs(col))/2 46 | local rowp = (row + torch.abs(row))/2 47 | 48 | assertEquals( posrowsum1, rowp:sum() ) 49 | assertEquals( posrowsum2, rowp:sum() ) 50 | assertEquals( poscolsum1, colp:sum() ) 51 | assertEquals( poscolsum2, colp:sum() ) 52 | end 53 | 54 | function testbenchmark() 55 | -- run a bunch of times 56 | for i = 1,100 do 57 | testfind1d() 58 | testfind2d() 59 | end 60 | end 61 | 62 | LuaUnit:main() 63 | -------------------------------------------------------------------------------- /fblualib/util/test/imports/a.lua: -------------------------------------------------------------------------------- 1 | return 1 2 | -------------------------------------------------------------------------------- /fblualib/util/test/imports/b/c.lua: -------------------------------------------------------------------------------- 1 | return 1000 2 | -------------------------------------------------------------------------------- /fblualib/util/test/imports/b/init.lua: -------------------------------------------------------------------------------- 1 | local util = require('fb.util') 2 | 3 | local a = 10 4 | a = a + util.import('..d') 5 | return a 6 | -------------------------------------------------------------------------------- /fblualib/util/test/imports/d.lua: -------------------------------------------------------------------------------- 1 | return 100 2 | -------------------------------------------------------------------------------- /fblualib/util/test/imports/init.lua: -------------------------------------------------------------------------------- 1 | local util = require('fb.util') 2 | 3 | local a = 0 4 | a = a + util.import('.a') 5 | a = a + util.import('.b') 6 | a = a + util.import('.b.c') 7 | 8 | return a 9 | -------------------------------------------------------------------------------- /fblualib/util/test/reactor_test.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | local pl = require('pl.import_into')() 11 | local reactor = require('fb.util.reactor') 12 | 13 | require('fb.luaunit') 14 | 15 | function testRun() 16 | local callback_ran 17 | local r = reactor.Reactor() 18 | r:run(function() 19 | callback_ran = true 20 | end) 21 | assertTrue(not callback_ran) 22 | assertEquals(1, r:loop_nb()) 23 | assertTrue(callback_ran) 24 | end 25 | 26 | function testRunAfterDelay() 27 | local callback_ran 28 | local r = reactor.Reactor() 29 | r:run_after_delay(0.05, function() 30 | callback_ran = true 31 | end) 32 | assertTrue(not callback_ran) 33 | assertEquals(1, r:loop()) 34 | assertTrue(callback_ran) 35 | end 36 | 37 | function testLoopForever() 38 | local callback_count = 0 39 | local r = reactor.Reactor() 40 | local function callback() 41 | callback_count = callback_count + 1 42 | if callback_count ~= 5 then 43 | r:run(callback) 44 | end 45 | end 46 | r:run(callback) 47 | assertEquals(5, r:loop_nb()) 48 | assertEquals(5, callback_count) 49 | assertEquals(0, r:loop_nb()) 50 | end 51 | 52 | function testRemoveCallback() 53 | local r = reactor.Reactor() 54 | local id = r:run(function() error('should not run') end) 55 | r:remove_callback(id) 56 | assertEquals(0, r:loop_nb()) 57 | end 58 | 59 | function testErrorPropagation() 60 | local r = reactor.Reactor() 61 | r:run(function() error('hello') end) 62 | local ok, err = pcall(function() r:loop_nb() end) 63 | assertFalse(ok) 64 | assertTrue(string.match(err, 'hello$')) 65 | end 66 | 67 | function testCoroutines() 68 | local done = false 69 | local r = reactor.Reactor() 70 | 71 | local function loop_until_done() 72 | while not done do 73 | r:loop_nb() 74 | end 75 | end 76 | 77 | local function terminate_loop() 78 | r:run(function() done = true end) 79 | end 80 | 81 | local function coroutine_func() 82 | -- First, scheduled from main and looping in coroutine 83 | loop_until_done() 84 | coroutine.yield(1) 85 | 86 | -- Second, scheduled from coroutine and looping in main 87 | terminate_loop() 88 | return 2 89 | end 90 | 91 | local c = coroutine.wrap(coroutine_func) 92 | 93 | -- First, scheduled from main and looping in coroutine 94 | terminate_loop() 95 | assertFalse(done) 96 | assertEquals(1, c()) 97 | assertTrue(done) 98 | done = false 99 | 100 | -- Second, scheduled from coroutine and looping in main 101 | assertEquals(2, c()) 102 | assertFalse(done) 103 | loop_until_done() 104 | assertTrue(done) 105 | end 106 | 107 | LuaUnit:main() 108 | -------------------------------------------------------------------------------- /fblualib/util/test/stats_test.lua: -------------------------------------------------------------------------------- 1 | require('fb.luaunit') 2 | local _debugger = require('fb.debugger') 3 | local Stats = require('fb.util.stats') 4 | 5 | 6 | Test = { 7 | EPS = 0.0001 8 | } 9 | 10 | function Test:testDefaultNew() 11 | local s = Stats.new() 12 | assertEquals(Stats.DEFAULT_DECAY_FACTOR, s.decay_factor); 13 | end 14 | 15 | function Test:testNewWithParams() 16 | local decay = 8.2 17 | local s = Stats.new("name", decay) 18 | assertEquals(decay, s.decay_factor) 19 | assertEquals("name", s.name) 20 | end 21 | 22 | function Test:testAddValue() 23 | local s = Stats.new() 24 | s:add(10) 25 | assertEquals(10, s.last_value) 26 | assertEquals(10, s.min) 27 | assertEquals(10, s.max) 28 | assertEquals(1, s.n) 29 | end 30 | 31 | function Test:testAvg() 32 | local s = Stats.new() 33 | s:add(10) 34 | s:add(20) 35 | assertEquals(15, s.avg) 36 | end 37 | 38 | function Test:testGetDAverage() 39 | local s = Stats.new() 40 | s:add(10) 41 | assertEquals(10, s.davg) 42 | s:add(10) 43 | assertEquals(10, s.davg) 44 | s:add(20) 45 | assertEquals(15, s.davg) 46 | s:add(20) 47 | assertEquals(17.5, s.davg) 48 | end 49 | 50 | function Test:testMin() 51 | local s = Stats.new() 52 | s:add(10) 53 | assertEquals(10, s.min) 54 | s:add(20) 55 | assertEquals(10, s.min) 56 | s:add(-20) 57 | assertEquals(-20, s.min) 58 | end 59 | 60 | function Test:testMax() 61 | local s = Stats.new() 62 | s:add(10) 63 | assertEquals(10, s.max) 64 | s:add(20) 65 | assertEquals(20, s.max) 66 | s:add(-20) 67 | assertEquals(20, s.max) 68 | end 69 | 70 | function Test:testVariance() 71 | local s = Stats.new() 72 | s:add(10) 73 | assertEquals(0, s:get_variance()) 74 | s:add(10) 75 | assertEquals(0, s:get_variance()) 76 | s:add(20) 77 | assertAlmostEquals(5.7735, s:get_variance(), Test.EPS) 78 | end 79 | 80 | function Test:testVariance() 81 | local s = Stats.new() 82 | s:add(10) 83 | assertEquals(0, s:get_dvariance()) 84 | s:add(10) 85 | assertEquals(0, s:get_dvariance()) 86 | s:add(20) 87 | assertAlmostEquals(5, s:get_dvariance(), Test.EPS) 88 | s:add(20) 89 | assertAlmostEquals(4.714, s:get_dvariance(), Test.EPS) 90 | end 91 | 92 | function Test:testN() 93 | local s = Stats.new() 94 | assertEquals(0, s.n) 95 | s:add(10) 96 | assertEquals(1, s.n) 97 | s:add(10) 98 | assertEquals(2, s.n) 99 | end 100 | 101 | function Test:testLastValue() 102 | local s = Stats.new() 103 | assertEquals(0, s.last_value) 104 | s:add(10) 105 | assertEquals(10, s.last_value) 106 | s:add(20) 107 | assertEquals(20, s.last_value) 108 | end 109 | 110 | function Test:testReset() 111 | local s = Stats.new() 112 | s:add(10) 113 | s:reset() 114 | assertEquals(0, s.n) 115 | assertEquals(0, s.avg) 116 | assertEquals(0, s.davg) 117 | assertEquals(0, s:get_dvariance()) 118 | assertEquals(math.huge, s.min) 119 | assertEquals(-math.huge, s.max) 120 | end 121 | 122 | function Test:testTotal() 123 | local s = Stats.new() 124 | assertEquals(0, s.total) 125 | s:add(10) 126 | assertEquals(10, s.total) 127 | s:add(5) 128 | assertEquals(15, s.total) 129 | end 130 | 131 | LuaUnit:main() 132 | -------------------------------------------------------------------------------- /fblualib/util/test/trace_test.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Copyright (c) 2014, Facebook, Inc. 3 | -- All rights reserved. 4 | -- 5 | -- This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | -- of patent rights can be found in the PATENTS file in the same directory. 8 | -- 9 | 10 | require('fb.luaunit') 11 | 12 | local pl = require('pl.import_into')() 13 | local trace = require('fb.util.trace') 14 | local timing = require('fb.util.timing') 15 | 16 | function testTrace() 17 | assertEquals({'foo', 'bar', 'baz', 'qux'}, 18 | trace.parse_key('foo:bar:baz:qux')) 19 | 20 | trace.namespace( 21 | 'foo:bar', 22 | function() 23 | assertEquals({'foo', 'bar', 'baz', 'qux'}, 24 | trace.parse_key('::baz:qux')) 25 | assertEquals({'meow', '', 'quack', 'ribbit'}, 26 | trace.parse_key('meow::quack:ribbit')) 27 | end) 28 | 29 | local log = {} 30 | local function handler(key, args, nest) 31 | -- Remove time value for easy comparison 32 | local args_copy = pl.tablex.copy(args) 33 | assertTrue(args_copy.time) 34 | args_copy.time = nil 35 | table.insert(log, {trace.format_key(key), args_copy, nest}) 36 | end 37 | 38 | -- everything under foo:ba.*, except foo:bar:baz 39 | trace.add_handler(handler, 'foo:bar:baz', true) 40 | trace.add_handler(handler, 'foo:ba.*') 41 | timing.add_pattern('foo:bar:baz', true) 42 | timing.add_pattern('foo:ba.*') 43 | timing.start('hello') 44 | 45 | trace.trace('foo:bar:x:y', {hello = 1}) 46 | trace.trace('foo:bar:baz:meow', {world = 2}) 47 | trace.trace('foo:bah:x:y', {goodbye = 3}) 48 | trace.trace('foo:boo:x:y', {woot = 4}) 49 | 50 | assertEquals({ 51 | {'foo:bar:x:y', {hello = 1}, 0}, 52 | {'foo:bah:x:y', {goodbye = 3}, 0}, 53 | }, log) 54 | 55 | log = {} 56 | 57 | trace.trace_function( 58 | 'foo:bar:x', 59 | function() 60 | trace.trace_function( 61 | '::y', 62 | function() 63 | trace.trace(':::inside', {hello = 1}) 64 | end, 65 | 10, 20) 66 | return 1, 2 67 | end, 68 | 30) 69 | 70 | local function strip_function_key(t) 71 | local ret = {} 72 | for k, v in pairs(t) do 73 | if k ~= 'func' then 74 | if type(v) == 'table' then 75 | ret[k] = strip_function_key(v) 76 | else 77 | ret[k] = v 78 | end 79 | end 80 | end 81 | return ret 82 | end 83 | 84 | assertEquals({ 85 | {'foo:bar:x:entry', {args = {30}}, 1}, 86 | {'foo:bar:y:entry', {args = {10, 20}}, 2}, 87 | {'foo:bar:y:inside', {hello = 1}, 2}, 88 | {'foo:bar:y:return', {ret = {}}, 2}, 89 | {'foo:bar:x:return', {ret = {1, 2}}, 1}, 90 | }, strip_function_key(log)) 91 | 92 | timing.finish() 93 | end 94 | 95 | LuaUnit:main() 96 | -------------------------------------------------------------------------------- /install_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Copyright (c) 2014, Facebook, Inc. 4 | # All rights reserved. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree. An additional grant 8 | # of patent rights can be found in the PATENTS file in the same directory. 9 | # 10 | 11 | echo 12 | echo This script will install fblualib and all its dependencies. 13 | echo It has been tested on Ubuntu 13.10 and Ubuntu 14.04, Linux x86_64. 14 | echo 15 | 16 | set -e 17 | set -x 18 | 19 | 20 | if [[ $(arch) != 'x86_64' ]]; then 21 | echo "x86_64 required" >&2 22 | exit 1 23 | fi 24 | 25 | issue=$(cat /etc/issue) 26 | extra_packages= 27 | current=0 28 | if [[ $issue =~ ^Ubuntu\ 13\.10 ]]; then 29 | : 30 | elif [[ $issue =~ ^Ubuntu\ 14 ]]; then 31 | extra_packages=libiberty-dev 32 | elif [[ $issue =~ ^Ubuntu\ 15\.04 ]]; then 33 | extra_packages=libiberty-dev 34 | elif [[ $issue =~ ^Ubuntu\ 16\.04 ]]; then 35 | extra_packages=libiberty-dev 36 | current=1 37 | else 38 | echo "Ubuntu 13.10, 14.*, 15.04 or 16.04 required" >&2 39 | exit 1 40 | fi 41 | 42 | dir=$(mktemp --tmpdir -d fblualib-build.XXXXXX) 43 | 44 | echo Working in $dir 45 | echo 46 | cd $dir 47 | 48 | echo Installing required packages 49 | echo 50 | sudo apt-get install -y \ 51 | git \ 52 | curl \ 53 | wget \ 54 | g++ \ 55 | automake \ 56 | autoconf \ 57 | autoconf-archive \ 58 | libtool \ 59 | libboost-all-dev \ 60 | libevent-dev \ 61 | libdouble-conversion-dev \ 62 | libgoogle-glog-dev \ 63 | libgflags-dev \ 64 | liblz4-dev \ 65 | liblzma-dev \ 66 | libsnappy-dev \ 67 | make \ 68 | zlib1g-dev \ 69 | binutils-dev \ 70 | libjemalloc-dev \ 71 | $extra_packages \ 72 | flex \ 73 | bison \ 74 | libkrb5-dev \ 75 | libsasl2-dev \ 76 | libnuma-dev \ 77 | pkg-config \ 78 | libssl-dev \ 79 | libedit-dev \ 80 | libmatio-dev \ 81 | libpython-dev \ 82 | libpython3-dev \ 83 | python-numpy 84 | 85 | echo 86 | echo Cloning repositories 87 | echo 88 | if [ $current -eq 1 ]; then 89 | git clone --depth 1 https://github.com/facebook/folly 90 | git clone --depth 1 https://github.com/facebook/fbthrift 91 | git clone https://github.com/facebook/thpp 92 | git clone https://github.com/facebook/fblualib 93 | git clone https://github.com/facebook/wangle 94 | else 95 | git clone -b v0.35.0 --depth 1 https://github.com/facebook/folly 96 | git clone -b v0.24.0 --depth 1 https://github.com/facebook/fbthrift 97 | git clone -b v1.0 https://github.com/facebook/thpp 98 | git clone -b v1.0 https://github.com/facebook/fblualib 99 | fi 100 | 101 | echo 102 | echo Building folly 103 | echo 104 | 105 | cd $dir/folly/folly 106 | autoreconf -ivf 107 | ./configure 108 | make 109 | sudo make install 110 | sudo ldconfig # reload the lib paths after freshly installed folly. fbthrift needs it. 111 | 112 | if [ $current -eq 1 ]; then 113 | echo 114 | echo Wangle 115 | echo 116 | 117 | cd $dir/wangle/wangle 118 | cmake . 119 | make 120 | sudo make install 121 | fi 122 | 123 | echo 124 | echo Building fbthrift 125 | echo 126 | 127 | cd $dir/fbthrift/thrift 128 | autoreconf -ivf 129 | ./configure 130 | if [ $current -eq 1 ]; then 131 | pushd lib/cpp2/fatal/internal 132 | ln -s folly_dynamic-inl-pre.h folly_dynamic-inl.h 133 | popd 134 | fi 135 | make 136 | sudo make install 137 | 138 | echo 139 | echo 'Installing TH++' 140 | echo 141 | 142 | cd $dir/thpp/thpp 143 | ./build.sh 144 | 145 | echo 146 | echo 'Installing FBLuaLib' 147 | echo 148 | 149 | cd $dir/fblualib/fblualib 150 | ./build.sh 151 | 152 | echo 153 | echo 'All done!' 154 | echo 155 | --------------------------------------------------------------------------------