From 7ce2da3be3b557d374fc22c049d7422f579142e6 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Wed, 16 Nov 2016 10:29:26 +0100 Subject: [PATCH] Rework client renderer setup This gets us rid of one unneeded socket based communication point which we kept around for historic reasons (from Android QEMU) but don't really need in our case. This allows a simplication of our setup and improves performance. --- external/android-emugl/CMakeLists.txt | 1 + .../host/include/OpenglRender/render_api.h | 56 --- .../OpenglRender/render_api_functions.h | 39 -- .../OpenglRender/render_api_platform_types.h | 39 -- .../host/include/libOpenglRender/IOStream.h | 16 +- src/CMakeLists.txt | 9 +- src/anbox/cmds/run.cpp | 3 +- src/anbox/common/small_vector.h | 383 ++++++++++++++++++ src/anbox/common/type_traits.h | 124 ++++++ src/anbox/graphics/buffer_queue.cpp | 98 +++++ src/anbox/graphics/buffer_queue.h | 61 +++ src/anbox/graphics/buffered_io_stream.cpp | 132 ++++++ src/anbox/graphics/buffered_io_stream.h | 63 +++ src/anbox/graphics/emugl/RenderApi.cpp | 217 +--------- .../emugl/{UnixStream.h => RenderApi.h} | 32 +- src/anbox/graphics/emugl/RenderServer.cpp | 137 ------- src/anbox/graphics/emugl/RenderServer.h | 41 -- src/anbox/graphics/emugl/RenderThread.cpp | 2 +- src/anbox/graphics/emugl/RenderWindow.cpp | 357 ---------------- src/anbox/graphics/emugl/RenderWindow.h | 122 ------ src/anbox/graphics/emugl/Renderer.cpp | 12 +- src/anbox/graphics/emugl/Renderer.h | 8 - src/anbox/graphics/emugl/SocketStream.cpp | 144 ------- src/anbox/graphics/emugl/SocketStream.h | 53 --- src/anbox/graphics/emugl/TcpStream.cpp | 70 ---- src/anbox/graphics/emugl/TcpStream.h | 33 -- src/anbox/graphics/emugl/UnixStream.cpp | 160 -------- src/anbox/graphics/gl_renderer_server.cpp | 57 ++- src/anbox/graphics/gl_renderer_server.h | 3 - src/anbox/graphics/layer_composer.cpp | 11 +- .../graphics/opengles_message_processor.cpp | 52 +-- .../graphics/opengles_message_processor.h | 14 +- src/anbox/graphics/rect.cpp | 3 +- src/anbox/network/base_socket_messenger.cpp | 11 + src/anbox/network/base_socket_messenger.h | 1 + src/anbox/network/message_sender.h | 2 + src/anbox/qemu/pipe_connection_creator.cpp | 15 +- src/anbox/qemu/pipe_connection_creator.h | 7 +- src/anbox/ubuntu/platform_policy.cpp | 6 +- 39 files changed, 998 insertions(+), 1596 deletions(-) delete mode 100644 external/android-emugl/host/include/OpenglRender/render_api.h delete mode 100644 external/android-emugl/host/include/OpenglRender/render_api_functions.h delete mode 100644 external/android-emugl/host/include/OpenglRender/render_api_platform_types.h create mode 100644 src/anbox/common/small_vector.h create mode 100644 src/anbox/common/type_traits.h create mode 100644 src/anbox/graphics/buffer_queue.cpp create mode 100644 src/anbox/graphics/buffer_queue.h create mode 100644 src/anbox/graphics/buffered_io_stream.cpp create mode 100644 src/anbox/graphics/buffered_io_stream.h rename src/anbox/graphics/emugl/{UnixStream.h => RenderApi.h} (51%) delete mode 100644 src/anbox/graphics/emugl/RenderServer.cpp delete mode 100644 src/anbox/graphics/emugl/RenderServer.h delete mode 100644 src/anbox/graphics/emugl/RenderWindow.cpp delete mode 100644 src/anbox/graphics/emugl/RenderWindow.h delete mode 100644 src/anbox/graphics/emugl/SocketStream.cpp delete mode 100644 src/anbox/graphics/emugl/SocketStream.h delete mode 100644 src/anbox/graphics/emugl/TcpStream.cpp delete mode 100644 src/anbox/graphics/emugl/TcpStream.h delete mode 100644 src/anbox/graphics/emugl/UnixStream.cpp diff --git a/external/android-emugl/CMakeLists.txt b/external/android-emugl/CMakeLists.txt index 29edadb..b328b17 100644 --- a/external/android-emugl/CMakeLists.txt +++ b/external/android-emugl/CMakeLists.txt @@ -3,6 +3,7 @@ set(CMAKE_C_FLAGS "-Wall") include_directories( + ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/external/android-emugl/shared ${CMAKE_SOURCE_DIR}/external/android-emugl/host/include ${CMAKE_SOURCE_DIR}/external/android-emugl/shared/OpenglCodecCommon diff --git a/external/android-emugl/host/include/OpenglRender/render_api.h b/external/android-emugl/host/include/OpenglRender/render_api.h deleted file mode 100644 index 0bcf485..0000000 --- a/external/android-emugl/host/include/OpenglRender/render_api.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#pragma once - -#include "OpenglRender/render_api_functions.h" - -#include - -/* This header and its declarations must be usable from C code. - * - * If RENDER_API_NO_PROTOTYPES is #defined before including this header, only - * the interface function pointer types will be declared, not the prototypes. - * This allows the client to use those names for its function pointer variables. - * - * All interfaces which can fail return an int, with zero indicating failure - * and anything else indicating success. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -// Use KHRONOS_APICALL to control visibility, but do not use KHRONOS_APIENTRY -// because we don't need the functions to be __stdcall on Win32. -#define RENDER_APICALL KHRONOS_APICALL -#define RENDER_APIENTRY - -#define RENDER_API_DECLARE(return_type, func_name, signature, callargs) \ - typedef return_type (RENDER_APIENTRY *func_name ## Fn) signature; \ - RENDER_APICALL return_type RENDER_APIENTRY func_name signature; - -typedef void (*emugl_logger_func_t)(const char* fmt, ...); - -typedef struct { - emugl_logger_func_t coarse; - emugl_logger_func_t fine; -} emugl_logger_struct; - -LIST_RENDER_API_FUNCTIONS(RENDER_API_DECLARE) - -#ifdef __cplusplus -} -#endif diff --git a/external/android-emugl/host/include/OpenglRender/render_api_functions.h b/external/android-emugl/host/include/OpenglRender/render_api_functions.h deleted file mode 100644 index 59237a8..0000000 --- a/external/android-emugl/host/include/OpenglRender/render_api_functions.h +++ /dev/null @@ -1,39 +0,0 @@ -// Auto-generated with: android/scripts/gen-entries.py --mode=funcargs distrib/android-emugl/host/libs/libOpenglRender/render_api.entries --output=distrib/android-emugl/host/include/OpenglRender/render_api_functions.h -// DO NOT EDIT THIS FILE - -#ifndef RENDER_API_FUNCTIONS_H -#define RENDER_API_FUNCTIONS_H - -#include "OpenglRender/render_api_platform_types.h" - -#include -#include -#include - -#include - -/* list of constants to be passed to setStreamMode */ -#define RENDER_API_STREAM_MODE_DEFAULT 0 -#define RENDER_API_STREAM_MODE_TCP 1 -#define RENDER_API_STREAM_MODE_UNIX 2 -#define RENDER_API_STREAM_MODE_PIPE 3 - -typedef void (*OnPostFn)(void* context, int width, int height, int ydir, - int format, int type, unsigned char* pixels); -typedef void (*emugl_crash_func_t)(const char* format, ...); - -#define LIST_RENDER_API_FUNCTIONS(X) \ - X(int, initLibrary, (), ()) \ - X(int, setStreamMode, (int mode), (mode)) \ - X(int, initOpenGLRenderer, (EGLNativeDisplayType native_display, char* addr, size_t addrLen, emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc), (native_display, addr, addrLen, logfuncs, crashfunc)) \ - X(void, getHardwareStrings, (const char** vendor, const char** renderer, const char** version), (vendor, renderer, version)) \ - X(void, setPostCallback, (OnPostFn onPost, void* onPostContext), (onPost, onPostContext)) \ - X(bool, showOpenGLSubwindow, (FBNativeWindowType window, int wx, int wy, int ww, int wh, int fbw, int fbh, float dpr, float zRot), (window, wx, wy, ww, wh, fbw, fbh, dpr, zRot)) \ - X(bool, destroyOpenGLSubwindow, (), ()) \ - X(void, setOpenGLDisplayRotation, (float zRot), (zRot)) \ - X(void, setOpenGLDisplayTranslation, (float px, float py), (px, py)) \ - X(void, repaintOpenGLDisplay, (), ()) \ - X(int, stopOpenGLRenderer, (), ()) \ - - -#endif // RENDER_API_FUNCTIONS_H diff --git a/external/android-emugl/host/include/OpenglRender/render_api_platform_types.h b/external/android-emugl/host/include/OpenglRender/render_api_platform_types.h deleted file mode 100644 index 12b993f..0000000 --- a/external/android-emugl/host/include/OpenglRender/render_api_platform_types.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -// Define FBNativeWindowType which corresponds to the type of native -// host UI window handles. - -#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ -#include - -typedef HWND FBNativeWindowType; - -#elif defined(__linux__) - -// Really a Window handle, but we don't want to include the X11 headers here. -#include -typedef uint32_t FBNativeWindowType; - -#elif defined(__APPLE__) - -typedef void* FBNativeWindowType; - -#else -#warning "Unsupported platform" -#endif diff --git a/external/android-emugl/host/include/libOpenglRender/IOStream.h b/external/android-emugl/host/include/libOpenglRender/IOStream.h index 672f5a7..3c28c93 100644 --- a/external/android-emugl/host/include/libOpenglRender/IOStream.h +++ b/external/android-emugl/host/include/libOpenglRender/IOStream.h @@ -23,7 +23,6 @@ class IOStream { public: - IOStream(size_t bufSize) { m_buf = NULL; m_bufsize = bufSize; @@ -31,19 +30,15 @@ public: } virtual void *allocBuffer(size_t minSize) = 0; - virtual int commitBuffer(size_t size) = 0; - virtual const unsigned char *readFully( void *buf, size_t len) = 0; - virtual const unsigned char *read( void *buf, size_t *inout_len) = 0; - virtual int writeFully(const void* buf, size_t len) = 0; + virtual size_t commitBuffer(size_t size) = 0; + virtual const unsigned char *read(void *buf, size_t *inout_len) = 0; virtual void forceStop() = 0; virtual ~IOStream() { - // NOTE: m_buf is 'owned' by the child class thus we expect it to be released by it } unsigned char *alloc(size_t len) { - if (m_buf && len > m_free) { if (flush() < 0) { ERR("Failed to flush in alloc\n"); @@ -70,7 +65,6 @@ public: } int flush() { - if (!m_buf || m_free == m_bufsize) return 0; int stat = commitBuffer(m_bufsize - m_free); @@ -79,12 +73,6 @@ public: return stat; } - const unsigned char *readback(void *buf, size_t len) { - flush(); - return readFully(buf, len); - } - - private: unsigned char *m_buf; size_t m_bufsize; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb7c899..e44ed22 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,6 +67,8 @@ set(SOURCES anbox/common/variable_length_array.h anbox/common/wait_handle.cpp anbox/common/dispatcher.cpp + anbox/common/small_vector.h + anbox/common/type_traits.h anbox/container/service.cpp anbox/container/client.cpp @@ -104,6 +106,8 @@ set(SOURCES anbox/rpc/make_protobuf_object.h anbox/graphics/opengles_message_processor.cpp + anbox/graphics/buffer_queue.cpp + anbox/graphics/buffered_io_stream.cpp anbox/graphics/gl_renderer_server.cpp anbox/graphics/density.h anbox/graphics/rect.cpp @@ -120,16 +124,11 @@ set(SOURCES anbox/graphics/emugl/RenderApi.cpp anbox/graphics/emugl/RenderContext.cpp anbox/graphics/emugl/RenderControl.cpp - anbox/graphics/emugl/RenderServer.cpp anbox/graphics/emugl/RenderThread.cpp anbox/graphics/emugl/RenderThreadInfo.cpp - anbox/graphics/emugl/RenderWindow.cpp - anbox/graphics/emugl/SocketStream.cpp - anbox/graphics/emugl/TcpStream.cpp anbox/graphics/emugl/TextureDraw.cpp anbox/graphics/emugl/TextureResize.cpp anbox/graphics/emugl/TimeUtils.cpp - anbox/graphics/emugl/UnixStream.cpp anbox/graphics/emugl/WindowSurface.cpp anbox/wm/display.cpp diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index e9b71de..e23e6ea 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -128,8 +128,7 @@ anbox::cmds::Run::Run(const BusFactory &bus_factory) auto qemu_pipe_connector = std::make_shared( utils::string_format("%s/qemu_pipe", config::socket_path()), rt, - std::make_shared( - rt, renderer->socket_path(), icon_)); + std::make_shared(rt)); auto bridge_connector = std::make_shared( utils::string_format("%s/anbox_bridge", config::socket_path()), rt, diff --git a/src/anbox/common/small_vector.h b/src/anbox/common/small_vector.h new file mode 100644 index 0000000..886620e --- /dev/null +++ b/src/anbox/common/small_vector.h @@ -0,0 +1,383 @@ +// Copyright 2016 The Android Open Source Project +// +// This software is licensed under the terms of the GNU General Public +// License version 2, as published by the Free Software Foundation, and +// may be copied, distributed, and modified under those terms. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#pragma once + +#include "anbox/common/type_traits.h" + +#include +#include +#include +#include + +#include +#include + +// +// SmallVector, SmallFixedVector +// +// This header defines a replacement for a std::vector<> that uses small buffer +// optimization technique - for some preset number of elements |SmallSize| it +// stores them inside of the object, and falls back to the dynamically allocated +// array only if one needs to add more elements. +// This is useful for the performance-critical places where common number of +// processed items is small, but it may still be quite large for a stack array. +// +// SmallFixedVector<> is the class you use to store elements, while +// SmallVector<> is its base class that erases the small size from the type. +// +// NOTE: SmallVector<> cannot guarantee std::vector<>'s iterator invalidation +// rules for move() and swap() operations - std::vector<>s just exchange +// their iterators on swap() and pass the moved ones over, while SmallVector<> +// may leave the iterators pointing to nowhere if they were for the in-place +// array storage. +// +// Currenly only a limited subset of std::vector<>'s operations is implemented, +// but fill free to add the ones you need. +// + +namespace anbox { +namespace common { + +// +// Forward-declare the 'real' small vector class. +template +class SmallFixedVector; + +// +// SmallVector - an interface for a small-buffer-optimized vector. +// It hides the fixed size from its type, so one can use it to pass small +// vectors around and not leak the buffer size to all callers: +// +// void process(SmallVector& data); +// ... +// ... +// SmallFixedVector aLittleBitOfFoos = ...; +// process(aLittleBitOfFoos); +// ... +// SmallFixedVector moreFoos = ...; +// process(moreFoos); +// +template +class SmallVector { + // Make them friends so SmallFixedVector is able to refer to SmallVector's + // protected members in static_assert()s. + template + friend class SmallFixedVector; + + public: + // Common set of type aliases. + using value_type = T; + using iterator = T*; + using const_iterator = const T*; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = size_t; + + // It's ok to delete SmallVector<> through the base class - dtor() actually + // takes care of all living elements and the allocated memory. + ~SmallVector() { dtor(); } + + // std::vector<> interface operations. + iterator begin() { return mBegin; } + const_iterator begin() const { return mBegin; } + const_iterator cbegin() const { return mBegin; } + + iterator end() { return mEnd; } + const_iterator end() const { return mEnd; } + const_iterator cend() const { return mEnd; } + + size_type size() const { return end() - begin(); } + size_type capacity() const { return mCapacity; } + bool empty() const { return begin() == end(); } + + reference operator[](size_t i) { return *(begin() + i); } + const_reference operator[](size_t i) const { return *(cbegin() + i); } + + pointer data() { return mBegin; } + const_pointer data() const { return mBegin; } + const_pointer cdata() const { return mBegin; } + + template + void emplace_back(Args&&... args) { + grow_for_size(size() + 1); + new (mEnd) T(std::forward(args)...); + ++mEnd; + } + + void push_back(const T& t) { emplace_back(t); } + void push_back(T&& t) { emplace_back(std::move(t)); } + + void clear() { + destruct(begin(), end()); + mEnd = mBegin; + } + + void reserve(size_type newCap) { + if (newCap <= this->capacity()) { + return; + } + set_capacity(newCap); + } + + void resize(size_type newSize) { resize_impl(newSize); } + + // This version of resizing doesn't initialize the newly allocated elements + // Useful for the cases when value-initialization is noticeably slow and + // one wants to directly construct or memcpy the elements into the resized + // place. + void resize_noinit(size_type newSize) { resize_impl(newSize); } + + // Returns if the current vector's buffer is dynamically allocated. + bool isAllocated() const { return this->cbegin() != smallBufferStart(); } + + protected: + // Hide the default constructor so only SmallFixedVector can be + // instantiated. + SmallVector() = default; + + // Destroy all elements in the vector and free the array if it was allocated + // dynamically. + void dtor() { + this->destruct(this->begin(), this->end()); + if (isAllocated()) { + free(this->mBegin); + } + } + + // Just a convenience setter function to init all members at once. + void init(iterator begin, iterator end, size_type capacity) { + this->mBegin = begin; + this->mEnd = end; + this->mCapacity = capacity; + } + + // An implementation of different resizing versions. + template + void resize_impl(size_type newSize) { + if (newSize < this->size()) { + const auto newEnd = this->begin() + newSize; + this->destruct(newEnd, this->end()); + this->mEnd = newEnd; + } else if (newSize > this->size()) { + grow_for_size(newSize); + const auto newEnd = this->begin() + newSize; + if (init) { + std::uninitialized_fill(this->end(), newEnd, T()); + } + this->mEnd = newEnd; + } + } + + // Templated append operation for a range of elements. + template + void insert_back(Iter b, Iter e) { + if (b == e) { + return; + } + const auto newSize = this->size() + (e - b); + grow_for_size(newSize); + this->mEnd = std::uninitialized_copy(b, e, this->mEnd); + } + + // Multiplicative grow for the internal array so it can hold |newSize| + // elements. + // Doesn't change size(), only capacity(). + void grow_for_size(size_type newSize) { + // Grow by 1.5x by default. + if (newSize > capacity()) { + set_capacity(std::max(newSize, capacity() + capacity() / 2)); + } + } + + // Sets the capacity() to be exacly |newCap|. Allocates the array + // dynamically, moves all elements over and (potentially) deallocates the + // old array. + // Doesn't change size(), only capacity(). + void set_capacity(size_type newCap) { + // Here we can only be switching to the dynamic vector, as static one + // always has its capacity on the maximum. + const auto newBegin = (T*)malloc(sizeof(T) * newCap); + if (!newBegin) { + abort(); // what else can we do here? + } + const auto newEnd = + std::uninitialized_copy(std::make_move_iterator(this->begin()), + std::make_move_iterator(this->end()), newBegin); + dtor(); + this->mBegin = newBegin; + this->mEnd = newEnd; + this->mCapacity = newCap; + } + + // A convenience function to call destructor for a range of elements. + static void destruct(T* b, T* e) { + if (!std::is_trivially_destructible::value) { + for (; b != e; ++b) { + b->~T(); + } + } + } + + // By design of the class, SmallFixedVector<> will be inheriting from + // SmallVector<>, so its in-place storage array is going to be the very next + // member after the last one here. + // This function returns that address, and SmallFixedVector<> has a static + // assert to make sure it remains correct. + constexpr const void* smallBufferStart() const { + return (const void*)(&mCapacity + 1); + } + + // Standard set of members for a vector - begin, end and capacity. + // These point to the currently used chunk of memory, no matter if it's a + // heap-allocated one or an in-place array. + iterator mBegin; + iterator mEnd; + size_type mCapacity; +}; + +// The implementation of a SmallVector with a fixed in-place size, |SmallSize|. +template +class SmallFixedVector : public SmallVector { + using base = SmallVector; + + public: + // Grab these from the base class. + using value_type = typename base::value_type; + using iterator = typename base::iterator; + using const_iterator = typename base::const_iterator; + using pointer = typename base::pointer; + using const_pointer = typename base::const_pointer; + using reference = typename base::reference; + using const_reference = typename base::const_reference; + using size_type = typename base::size_type; + + static constexpr size_type kSmallSize = SmallSize; + + // Default constructor - set up an empty vector with capacity at full + // internal array size. + SmallFixedVector() { + // Make sure that the small array starts exactly where base class + // expects it: right after the |mCapacity|. + static_assert(offsetof(base, mCapacity) + sizeof(base::mCapacity) == + offsetof(SmallFixedVector, mData) && + offsetof(Data, array) == 0, + "SmallFixedVector<> class layout is wrong, " + "|mData| needs to follow |mCapacity|"); + + init_inplace(); + } + + // Ctor from a range of iterators + template + SmallFixedVector(Iter b, Iter e) : SmallFixedVector() { + this->insert_back(b, e); + } + + // Ctor from a range - anything that has begin and end. + // Note: template constructor is never a copy/move-ctor. + template ::value && + is_range::value>> + explicit SmallFixedVector(const Range& r) + : SmallFixedVector(std::begin(r), std::end(r)) {} + template ::value && + is_range::value>> + explicit SmallFixedVector(Range&& r) + : SmallFixedVector(std::make_move_iterator(std::begin(r)), + std::make_move_iterator(std::end(r))) {} + template > + SmallFixedVector(std::initializer_list list) + : SmallFixedVector(std::begin(list), std::end(list)) {} + + SmallFixedVector(const SmallFixedVector& other) + : SmallFixedVector(other.begin(), other.end()) {} + + SmallFixedVector(SmallFixedVector&& other) { + if (other.isAllocated()) { + // Just steal the allocated memory from the |other|. + this->mBegin = other.mBegin; + this->mEnd = other.mEnd; + this->mCapacity = other.mCapacity; + other.init_inplace(); + } else { + // Have to move individual elements. + this->mBegin = mData.array; + this->mEnd = std::uninitialized_copy( + std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end()), this->begin()); + this->mCapacity = kSmallSize; + } + } + + SmallFixedVector& operator=(const SmallFixedVector& other) { + if (&other != this) { + this->clear(); + this->insert_back(other.begin(), other.end()); + } + return *this; + } + + SmallFixedVector& operator=(SmallFixedVector&& other) { + if (other.isAllocated()) { + // Steal it and we're done. + this->dtor(); + this->mBegin = other.mBegin; + this->mEnd = other.mEnd; + this->mCapacity = other.mCapacity; + other.init_inplace(); + return *this; + } + + if (this->isAllocated() && this->mCapacity < other.size()) { + // Not enough dynamic memory, switch to in-place. + this->dtor(); + init_inplace(); + } else { + // This could potentially be improved by move-assigning + // only needed items and destroying the rest, but + // destroy-all+construct-all is just simpler. For PODs it actually + // is even faster as it's always a single memcpy(). + this->destruct(this->begin(), this->end()); + } + + // Move the whole |other| into the pre-cleaned memory + const auto newEnd = std::uninitialized_copy( + std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end()), this->mBegin); + this->mEnd = newEnd; + // |other| is valid as-is. + return *this; + } + + // Make sure we don't end up trying to move from an interface - it's just + // inefficient with the current code. + SmallFixedVector(base&& other) = delete; + SmallFixedVector& operator=(base&& other) = delete; + + private: + // A shortcut for initialization for in-place storage. + void init_inplace() { this->init(mData.array, mData.array, kSmallSize); } + + // A union with empty constructor and destructor makes sure that the array + // elements are not default-constructed in ctor and not destructed in dtor: + // the class needs to be able manage their lifetime more precisely. + union Data { + alignas(size_type) T array[kSmallSize]; + + Data() {} + ~Data() {} + } mData; +}; + +} // namespace common +} // namespace anbox diff --git a/src/anbox/common/type_traits.h b/src/anbox/common/type_traits.h new file mode 100644 index 0000000..eb7a192 --- /dev/null +++ b/src/anbox/common/type_traits.h @@ -0,0 +1,124 @@ +// Copyright 2015 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +namespace anbox { +namespace common { + +namespace details { + +// a simple helper class for SFINAE below. +template +struct dummy { + using type = X; +}; + +} // namespaces details + +// add some convenience shortcuts for an overly complex std::enable_if syntax + +// Use 'enable_if' instead of +// 'typename std::enable_if::type' +template +using enable_if = typename std::enable_if::type; + +// Use 'enable_if_c' instead of +// 'typename std::enable_if::type' +template +using enable_if_c = typename std::enable_if::type; + +// Use 'enable_if_convertible' instead of +// 'typename std::enable_if::value, Type>::type' +template +using enable_if_convertible = enable_if>; + +// ----------------------------------------------------------------------------- +// A predicate for checking if some object is callable with a specific +// signature. Examples: +// +// is_callable_as::value == false. +// is_callable_as::value == false. +// is_callable_as::value == true +// +template +struct is_callable_as : std::false_type {}; + +// This specialization is SFINAE-d out if template arguments can't be combined +// into a call expression F(), or if the result of that call is not |R| +template +struct is_callable_as< + F, R(), typename std::enable_if()())>::type, + R>::value>::type> : std::true_type {}; + +// One more specialization, for non empty argument list +template +struct is_callable_as()( + std::declval()...))>::type, + R>::value>::type> : std::true_type {}; +// ----------------------------------------------------------------------------- +// Check if a type |T| is any instantiation of a template |U|. Examples: +// +// is_template_instantiation_of::value == false +// is_template_instantiation_of< +// std::list>, std::vector>::value == false +// is_template_instantiation_of, std::vector>::value == true +// is_template_instantiation_of< +// std::vector>, std::vector>::value == true +// +template class U> +struct is_template_instantiation_of : std::false_type {}; + +template