Commit 9662a6a5 authored by Kenton Varda's avatar Kenton Varda Committed by Kenton Varda

MSVC: Build and test parts of KJ needed in lite mode.

Thanks to Bryan Boreham <bjboreham@gmail.com> for much help getting this started.
parent 0d6b9704
...@@ -5,8 +5,9 @@ under the same MIT license terms as the rest of the library. ...@@ -5,8 +5,9 @@ under the same MIT license terms as the rest of the library.
Kenton Varda <temporal@gmail.com>: Primary Author Kenton Varda <temporal@gmail.com>: Primary Author
Jason Choy <jjwchoy@gmail.com>: kj/threadlocal.h and other iOS tweaks, `name` annotation in C++ code generator Jason Choy <jjwchoy@gmail.com>: kj/threadlocal.h and other iOS tweaks, `name` annotation in C++ code generator
Remy Blank <rblank@google.com> (contributions copyright Google Inc.): KJ Timers Remy Blank <rblank@google.com> (contributions copyright Google Inc.): KJ Timers
Joshua Warner <joshuawarner32@gmail.com>: cmake build Joshua Warner <joshuawarner32@gmail.com>: cmake build, AnyStruct/AnyList, other stuff
Scott Purdy <scott@fer.io>: kj/std iostream interface Scott Purdy <scott@fer.io>: kj/std iostream interface
Bryan Borham <bjboreham@gmail.com>: Initial MSVC support
This file does not list people who maintain their own Cap'n Proto This file does not list people who maintain their own Cap'n Proto
implementations as separate projects. Those people are awesome too! :) implementations as separate projects. Those people are awesome too! :)
...@@ -136,6 +136,7 @@ includekj_HEADERS = \ ...@@ -136,6 +136,7 @@ includekj_HEADERS = \
src/kj/exception.h \ src/kj/exception.h \
src/kj/debug.h \ src/kj/debug.h \
src/kj/arena.h \ src/kj/arena.h \
src/kj/miniposix.h \
src/kj/io.h \ src/kj/io.h \
src/kj/tuple.h \ src/kj/tuple.h \
src/kj/one-of.h \ src/kj/one-of.h \
......

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22310.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "capnproto", "capnproto.vcxproj", "{CD7EEDAE-3D48-4402-9F60-EC23311BE143}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\gtest\msvc\gtest.vcxproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "..\gtest\msvc\gtest_main.vcxproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Debug|Win32.ActiveCfg = Debug|Win32
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Debug|Win32.Build.0 = Debug|Win32
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Release|Win32.ActiveCfg = Release|Win32
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Release|Win32.Build.0 = Release|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.ActiveCfg = Debug|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.Build.0 = Debug|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.ActiveCfg = Release|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.Build.0 = Release|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.ActiveCfg = Debug|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.Build.0 = Debug|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.ActiveCfg = Release|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CD7EEDAE-3D48-4402-9F60-EC23311BE143}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;CAPNP_LITE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<AdditionalOptions>/TP %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;CAPNP_LITE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalOptions>/TP %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\src\kj\array.h" />
<ClInclude Include="..\src\kj\common.h" />
<ClInclude Include="..\src\kj\debug.h" />
<ClInclude Include="..\src\kj\exception.h" />
<ClInclude Include="..\src\kj\io.h" />
<ClInclude Include="..\src\kj\memory.h" />
<ClInclude Include="..\src\kj\string.h" />
<ClInclude Include="..\src\kj\miniposix.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\kj\array-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\array.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\common-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\common.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\debug-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\debug.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\exception-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\exception.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\io-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\io.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\memory-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\memory.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\string-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\string.c++">
<FileType>Document</FileType>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\gtest\msvc\gtest.vcxproj">
<Project>{c8f6c172-56f2-4e76-b5fa-c3b423b31be7}</Project>
</ProjectReference>
<ProjectReference Include="..\gtest\msvc\gtest_main.vcxproj">
<Project>{3af54c8a-10bf-4332-9147-f68ed9862032}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
MSVC project files
As of this writing, this MSVC project is very basic: all it does is compile a
unit test covering all lite-mode functionality. In the long run, we intend for
MSVC libraries to be compiled using the cmake files. This project is a stopgap
because Kenton doesn't understand cmake and wanted to get some work done.
The solution file refers to gtest, which must be downloaded to "c++/gtest".
The "setup-autotools.sh" script accomplishes this, although it requires bash
to run.
...@@ -30,6 +30,7 @@ set(kj_headers ...@@ -30,6 +30,7 @@ set(kj_headers
exception.h exception.h
debug.h debug.h
arena.h arena.h
miniposix.h
io.h io.h
tuple.h tuple.h
one-of.h one-of.h
......
...@@ -446,7 +446,7 @@ class CappedArray { ...@@ -446,7 +446,7 @@ class CappedArray {
// TODO(someday): Don't construct elements past currentSize? // TODO(someday): Don't construct elements past currentSize?
public: public:
inline constexpr CappedArray(): currentSize(fixedSize) {} inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {}
inline explicit constexpr CappedArray(size_t s): currentSize(s) {} inline explicit constexpr CappedArray(size_t s): currentSize(s) {}
inline size_t size() const { return currentSize; } inline size_t size() const { return currentSize; }
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#endif #endif
#ifndef KJ_NO_COMPILER_CHECK #ifndef KJ_NO_COMPILER_CHECK
#if __cplusplus < 201103L && !__CDT_PARSER__ #if __cplusplus < 201103L && !__CDT_PARSER__ && !_MSC_VER
#error "This code requires C++11. Either your compiler does not support it or it is not enabled." #error "This code requires C++11. Either your compiler does not support it or it is not enabled."
#ifdef __GNUC__ #ifdef __GNUC__
// Compiler claims compatibility with GCC, so presumably supports -std. // Compiler claims compatibility with GCC, so presumably supports -std.
...@@ -61,7 +61,12 @@ ...@@ -61,7 +61,12 @@
#endif #endif
#endif #endif
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#warning "As of June 2013, Visual Studio's C++11 support was hopelessly behind what is needed to compile this code." #if _MSC_VER < 1900
#error "You need Visual Studio 2015 or better to compile this code."
#elif !CAPNP_LITE
// TODO(cleanup): This is KJ, but we're talking about Cap'n Proto.
#error "As of this writing, Cap'n Proto only supports Visual C++ in 'lite mode'; please #define CAPNP_LITE"
#endif
#else #else
#warning "I don't recognize your compiler. As of this writing, Clang and GCC are the only "\ #warning "I don't recognize your compiler. As of this writing, Clang and GCC are the only "\
"known compilers with enough C++11 support for this library. "\ "known compilers with enough C++11 support for this library. "\
...@@ -104,7 +109,7 @@ typedef unsigned char byte; ...@@ -104,7 +109,7 @@ typedef unsigned char byte;
#if !defined(KJ_DEBUG) && !defined(KJ_NDEBUG) #if !defined(KJ_DEBUG) && !defined(KJ_NDEBUG)
// Heuristically decide whether to enable debug mode. If DEBUG or NDEBUG is defined, use that. // Heuristically decide whether to enable debug mode. If DEBUG or NDEBUG is defined, use that.
// Otherwise, fall back to checking whether optimization is enabled. // Otherwise, fall back to checking whether optimization is enabled.
#if defined(DEBUG) #if defined(DEBUG) || defined(_DEBUG)
#define KJ_DEBUG #define KJ_DEBUG
#elif defined(NDEBUG) #elif defined(NDEBUG)
#define KJ_NDEBUG #define KJ_NDEBUG
...@@ -120,11 +125,16 @@ typedef unsigned char byte; ...@@ -120,11 +125,16 @@ typedef unsigned char byte;
classname& operator=(const classname&) = delete classname& operator=(const classname&) = delete
// Deletes the implicit copy constructor and assignment operator. // Deletes the implicit copy constructor and assignment operator.
#ifdef __GNUC__
#define KJ_LIKELY(condition) __builtin_expect(condition, true) #define KJ_LIKELY(condition) __builtin_expect(condition, true)
#define KJ_UNLIKELY(condition) __builtin_expect(condition, false) #define KJ_UNLIKELY(condition) __builtin_expect(condition, false)
// Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we // Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we
// expect the condition to be true/false enough of the time that it's worth hard-coding branch // expect the condition to be true/false enough of the time that it's worth hard-coding branch
// prediction. // prediction.
#else
#define KJ_LIKELY(condition) (condition)
#define KJ_UNLIKELY(condition) (condition)
#endif
#if defined(KJ_DEBUG) || __NO_INLINE__ #if defined(KJ_DEBUG) || __NO_INLINE__
#define KJ_ALWAYS_INLINE(prototype) inline prototype #define KJ_ALWAYS_INLINE(prototype) inline prototype
...@@ -140,13 +150,16 @@ typedef unsigned char byte; ...@@ -140,13 +150,16 @@ typedef unsigned char byte;
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define KJ_NORETURN(prototype) __declspec(noreturn) prototype #define KJ_NORETURN(prototype) __declspec(noreturn) prototype
#define KJ_UNUSED
#define KJ_WARN_UNUSED_RESULT
// TODO(msvc): KJ_WARN_UNUSED_RESULT can use _Check_return_ on MSVC, but it's a prefix, so
// wrapping the whole prototype is needed. http://msdn.microsoft.com/en-us/library/jj159529.aspx
// Similarly, KJ_UNUSED could use __pragma(warning(suppress:...)), but again that's a prefix.
#else #else
#define KJ_NORETURN(prototype) prototype __attribute__((noreturn)) #define KJ_NORETURN(prototype) prototype __attribute__((noreturn))
#endif
#define KJ_UNUSED __attribute__((unused)) #define KJ_UNUSED __attribute__((unused))
#define KJ_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #define KJ_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#endif
#if __clang__ #if __clang__
#define KJ_UNUSED_MEMBER __attribute__((unused)) #define KJ_UNUSED_MEMBER __attribute__((unused))
...@@ -159,9 +172,12 @@ typedef unsigned char byte; ...@@ -159,9 +172,12 @@ typedef unsigned char byte;
#if __clang__ #if __clang__
#define KJ_DEPRECATED(reason) \ #define KJ_DEPRECATED(reason) \
__attribute__((deprecated(reason))) __attribute__((deprecated(reason)))
#else #elif __GNUC__
#define KJ_DEPRECATED(reason) \ #define KJ_DEPRECATED(reason) \
__attribute__((deprecated)) __attribute__((deprecated))
#else
#define KJ_DEPRECATED(reason)
// TODO(msvc): Again, here, MSVC prefers a prefix, __declspec(deprecated).
#endif #endif
namespace _ { // private namespace _ { // private
...@@ -178,6 +194,22 @@ KJ_NORETURN(void unreachable()); ...@@ -178,6 +194,22 @@ KJ_NORETURN(void unreachable());
} // namespace _ (private) } // namespace _ (private)
#ifdef KJ_DEBUG #ifdef KJ_DEBUG
#if _MSC_VER
// TODO(msvc): Figure out __VA_ARGS__; see debug.h.
#define KJ_IREQUIRE(condition, ...) \
if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \
__FILE__, __LINE__, #condition, "")
// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to
// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that
// it will be enabled depending on whether the application is compiled in debug mode rather than
// whether libkj is.
#define KJ_IASSERT(condition, ...) \
if (KJ_LIKELY(condition)); else ::kj::_::inlineAssertFailure( \
__FILE__, __LINE__, #condition, "")
// Version of KJ_DASSERT() which is safe to use in headers that are #included by users. Used to
// check state inside inline and templated methods.
#else
#define KJ_IREQUIRE(condition, ...) \ #define KJ_IREQUIRE(condition, ...) \
if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \
__FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__) __FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__)
...@@ -191,6 +223,7 @@ KJ_NORETURN(void unreachable()); ...@@ -191,6 +223,7 @@ KJ_NORETURN(void unreachable());
__FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__) __FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__)
// Version of KJ_DASSERT() which is safe to use in headers that are #included by users. Used to // Version of KJ_DASSERT() which is safe to use in headers that are #included by users. Used to
// check state inside inline and templated methods. // check state inside inline and templated methods.
#endif
#else #else
#define KJ_IREQUIRE(condition, ...) #define KJ_IREQUIRE(condition, ...)
#define KJ_IASSERT(condition, ...) #define KJ_IASSERT(condition, ...)
...@@ -212,11 +245,11 @@ KJ_NORETURN(void unreachable()); ...@@ -212,11 +245,11 @@ KJ_NORETURN(void unreachable());
// variable-sized arrays. For other compilers we could just use a fixed-size array. `minStack` // variable-sized arrays. For other compilers we could just use a fixed-size array. `minStack`
// is the stack array size to use if variable-width arrays are not supported. `maxStack` is the // is the stack array size to use if variable-width arrays are not supported. `maxStack` is the
// maximum stack array size if variable-width arrays *are* supported. // maximum stack array size if variable-width arrays *are* supported.
#if __clang__ #if __GNUC__ && !__clang__
#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \
size_t name##_size = (size); \ size_t name##_size = (size); \
bool name##_isOnStack = name##_size <= (minStack); \ bool name##_isOnStack = name##_size <= (maxStack); \
type name##_stack[minStack]; \ type name##_stack[name##_isOnStack ? size : 0]; \
::kj::Array<type> name##_heap = name##_isOnStack ? \ ::kj::Array<type> name##_heap = name##_isOnStack ? \
nullptr : kj::heapArray<type>(name##_size); \ nullptr : kj::heapArray<type>(name##_size); \
::kj::ArrayPtr<type> name = name##_isOnStack ? \ ::kj::ArrayPtr<type> name = name##_isOnStack ? \
...@@ -224,8 +257,8 @@ KJ_NORETURN(void unreachable()); ...@@ -224,8 +257,8 @@ KJ_NORETURN(void unreachable());
#else #else
#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \
size_t name##_size = (size); \ size_t name##_size = (size); \
bool name##_isOnStack = name##_size <= (maxStack); \ bool name##_isOnStack = name##_size <= (minStack); \
type name##_stack[name##_isOnStack ? size : 0]; \ type name##_stack[minStack]; \
::kj::Array<type> name##_heap = name##_isOnStack ? \ ::kj::Array<type> name##_heap = name##_isOnStack ? \
nullptr : kj::heapArray<type>(name##_size); \ nullptr : kj::heapArray<type>(name##_size); \
::kj::ArrayPtr<type> name = name##_isOnStack ? \ ::kj::ArrayPtr<type> name = name##_isOnStack ? \
...@@ -238,6 +271,32 @@ KJ_NORETURN(void unreachable()); ...@@ -238,6 +271,32 @@ KJ_NORETURN(void unreachable());
// Create a unique identifier name. We use concatenate __LINE__ rather than __COUNTER__ so that // Create a unique identifier name. We use concatenate __LINE__ rather than __COUNTER__ so that
// the name can be used multiple times in the same macro. // the name can be used multiple times in the same macro.
#if _MSC_VER
#define KJ_CONSTEXPR(...) __VA_ARGS__
// Use in cases where MSVC barfs on constexpr. A replacement keyword (e.g. "const") can be
// provided, or just leave blank to remove the keyword entirely.
//
// TODO(msvc): Remove this hack once MSVC fully supports constexpr.
#ifndef __restrict__
#define __restrict__ __restrict
// TODO(msvc): Would it be better to define a KJ_RESTRICT macro?
#endif
#pragma warning(disable: 4521 4522)
// This warning complains when there are two copy constructors, one for a const reference and
// one for a non-const reference. It is often quite necessary to do this in wrapper templates,
// therefore this warning is dumb and we disable it.
#pragma warning(disable: 4458)
// Warns when a parameter name shadows a class member. Unfortunately my code does this a lot,
// since I don't use a special name format for members.
#else // _MSC_VER
#define KJ_CONSTEXPR(...) constexpr
#endif
// ======================================================================================= // =======================================================================================
// Template metaprogramming helpers. // Template metaprogramming helpers.
...@@ -403,9 +462,14 @@ template<typename T> constexpr T cp(const T& t) noexcept { return t; } ...@@ -403,9 +462,14 @@ template<typename T> constexpr T cp(const T& t) noexcept { return t; }
// Useful to force a copy, particularly to pass into a function that expects T&&. // Useful to force a copy, particularly to pass into a function that expects T&&.
template <typename T, typename U> template <typename T, typename U>
inline constexpr auto min(T&& a, U&& b) -> decltype(a < b ? a : b) { return a < b ? a : b; } inline KJ_CONSTEXPR() auto min(T&& a, U&& b) -> Decay<decltype(a < b ? a : b)> {
return a < b ? a : b;
}
template <typename T, typename U> template <typename T, typename U>
inline constexpr auto max(T&& a, U&& b) -> decltype(a > b ? a : b) { return a > b ? a : b; } inline KJ_CONSTEXPR() auto max(T&& a, U&& b) -> Decay<decltype(a > b ? a : b)> {
return a > b ? a : b;
}
template <typename T, size_t s> template <typename T, size_t s>
inline constexpr size_t size(T (&arr)[s]) { return s; } inline constexpr size_t size(T (&arr)[s]) { return s; }
...@@ -474,22 +538,33 @@ public: ...@@ -474,22 +538,33 @@ public:
} }
}; };
static constexpr MaxValue_ maxValue = MaxValue_(); static KJ_CONSTEXPR(const) MaxValue_ maxValue = MaxValue_();
// A special constant which, when cast to an integer type, takes on the maximum possible value of // A special constant which, when cast to an integer type, takes on the maximum possible value of
// that type. This is useful to use as e.g. a parameter to a function because it will be robust // that type. This is useful to use as e.g. a parameter to a function because it will be robust
// in the face of changes to the parameter's type. // in the face of changes to the parameter's type.
// //
// `char` is not supported, but `signed char` and `unsigned char` are. // `char` is not supported, but `signed char` and `unsigned char` are.
static constexpr MinValue_ minValue = MinValue_(); static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_();
// A special constant which, when cast to an integer type, takes on the minimum possible value // A special constant which, when cast to an integer type, takes on the minimum possible value
// of that type. This is useful to use as e.g. a parameter to a function because it will be robust // of that type. This is useful to use as e.g. a parameter to a function because it will be robust
// in the face of changes to the parameter's type. // in the face of changes to the parameter's type.
// //
// `char` is not supported, but `signed char` and `unsigned char` are. // `char` is not supported, but `signed char` and `unsigned char` are.
#if __GNUC__
inline constexpr float inf() { return __builtin_huge_valf(); } inline constexpr float inf() { return __builtin_huge_valf(); }
inline constexpr float nan() { return __builtin_nanf(""); } inline constexpr float nan() { return __builtin_nanf(""); }
#elif _MSC_VER
// Do what MSVC math.h does
#pragma warning(push)
#pragma warning(disable: 4756) // "overflow in constant arithmetic"
inline constexpr float inf() { return (float)(1e300 * 1e300); }
#pragma warning(pop)
inline constexpr float nan() { return inf() * 0.0F; }
#else
#error "Not sure how to support your compiler."
#endif
// ======================================================================================= // =======================================================================================
// Useful fake containers // Useful fake containers
...@@ -624,6 +699,8 @@ inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept { ...@@ -624,6 +699,8 @@ inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept {
return __p; return __p;
} }
inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {}
namespace kj { namespace kj {
template <typename T, typename... Params> template <typename T, typename... Params>
...@@ -793,10 +870,22 @@ private: // internal interface used by friends only ...@@ -793,10 +870,22 @@ private: // internal interface used by friends only
private: private:
bool isSet; bool isSet;
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4624)
// Warns that the anonymous union has a deleted destructor when T is non-trivial. This warning
// seems broken.
#endif
union { union {
T value; T value;
}; };
#if _MSC_VER
#pragma warning(pop)
#endif
friend class kj::Maybe<T>; friend class kj::Maybe<T>;
template <typename U> template <typename U>
friend NullableValue<U>&& readMaybe(Maybe<U>&& maybe); friend NullableValue<U>&& readMaybe(Maybe<U>&& maybe);
...@@ -981,7 +1070,7 @@ public: ...@@ -981,7 +1070,7 @@ public:
inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {} inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {}
inline constexpr ArrayPtr(T* ptr, size_t size): ptr(ptr), size_(size) {} inline constexpr ArrayPtr(T* ptr, size_t size): ptr(ptr), size_(size) {}
inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {} inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {}
inline constexpr ArrayPtr(std::initializer_list<RemoveConstOrDisable<T>> init) inline KJ_CONSTEXPR() ArrayPtr(std::initializer_list<RemoveConstOrDisable<T>> init)
: ptr(init.begin()), size_(init.size()) {} : ptr(init.begin()), size_(init.size()) {}
template <size_t size> template <size_t size>
......
...@@ -24,17 +24,22 @@ ...@@ -24,17 +24,22 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string> #include <string>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <exception> #include <exception>
#include "miniposix.h"
#if !_WIN32 #if !_WIN32
#include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
#if _MSC_VER
#pragma warning(disable: 4996)
// Warns that sprintf() is buffer-overrunny. Yeah, I know, it's cool.
#endif
namespace kj { namespace kj {
namespace _ { // private namespace _ { // private
namespace { namespace {
...@@ -115,7 +120,7 @@ public: ...@@ -115,7 +120,7 @@ public:
const char* end = pos + text.size(); const char* end = pos + text.size();
while (pos < end) { while (pos < end) {
ssize_t n = write(outputPipe, pos, end - pos); miniposix::ssize_t n = miniposix::write(outputPipe, pos, end - pos);
if (n < 0) { if (n < 0) {
if (errno == EINTR) { if (errno == EINTR) {
continue; continue;
...@@ -319,6 +324,16 @@ TEST(Debug, Catch) { ...@@ -319,6 +324,16 @@ TEST(Debug, Catch) {
#endif #endif
} }
int mockSyscall(int i, int error = 0) {
errno = error;
return i;
}
int fail() {
errno = EBADF;
return -1;
}
TEST(Debug, Syscall) { TEST(Debug, Syscall) {
MockExceptionCallback mockCallback; MockExceptionCallback mockCallback;
int line; int line;
...@@ -326,19 +341,21 @@ TEST(Debug, Syscall) { ...@@ -326,19 +341,21 @@ TEST(Debug, Syscall) {
int i = 123; int i = 123;
const char* str = "foo"; const char* str = "foo";
int fd; KJ_SYSCALL(mockSyscall(0));
KJ_SYSCALL(fd = dup(STDIN_FILENO)); KJ_SYSCALL(mockSyscall(1));
KJ_SYSCALL(close(fd));
EXPECT_FATAL(KJ_SYSCALL(close(fd), i, "bar", str)); line = __LINE__; EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, EBADF), i, "bar", str)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": error from OS: close(fd): " EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) +
+ strerror(EBADF) + "; i = 123; bar; str = foo\n", mockCallback.text); ": error from OS: mockSyscall(-1, EBADF): " + strerror(EBADF) +
"; i = 123; bar; str = foo\n", mockCallback.text);
mockCallback.text.clear(); mockCallback.text.clear();
int result = 0; int result = 0;
bool recovered = false; bool recovered = false;
KJ_SYSCALL(result = close(fd), i, "bar", str) { recovered = true; break; } line = __LINE__; KJ_SYSCALL(result = mockSyscall(-2, EBADF), i, "bar", str) { recovered = true; break; } line = __LINE__;
EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) + ": error from OS: close(fd): " EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) +
+ strerror(EBADF) + "; i = 123; bar; str = foo\n", mockCallback.text); ": error from OS: mockSyscall(-2, EBADF): " + strerror(EBADF) +
"; i = 123; bar; str = foo\n", mockCallback.text);
EXPECT_LT(result, 0); EXPECT_LT(result, 0);
EXPECT_TRUE(recovered); EXPECT_TRUE(recovered);
} }
......
...@@ -121,6 +121,81 @@ ...@@ -121,6 +121,81 @@
namespace kj { namespace kj {
#if _MSC_VER
// MSVC does __VA_ARGS__ differently from GCC:
// - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants
// you to request this behavior with "##__VA_ARGS__".
// - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a
// *single* argument rather than an argument list. This can be worked around by wrapping the
// outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before
// the macro is evaluated. I don't understand the C preprocessor.
// - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is
// empty, rather than expanding to an empty string literal. We can work around by concatenating
// with an empty string literal.
#define KJ_EXPAND(X) X
#define KJ_LOG(severity, ...) \
if (!::kj::_::Debug::shouldLog(::kj::_::Debug::Severity::severity)) {} else \
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::_::Debug::Severity::severity, \
"" #__VA_ARGS__, __VA_ARGS__)
#define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__))
#define _kJ_FAULT(nature, cond, ...) \
if (KJ_LIKELY(cond)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Nature::nature, 0, \
#cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define _kJ_FAIL_FAULT(nature, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Nature::nature, 0, \
nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_ASSERT(...) KJ_EXPAND(_kJ_FAULT(LOCAL_BUG, __VA_ARGS__))
#define KJ_REQUIRE(...) KJ_EXPAND(_kJ_FAULT(PRECONDITION, __VA_ARGS__))
#define KJ_FAIL_ASSERT(...) KJ_EXPAND(_kJ_FAIL_FAULT(LOCAL_BUG, __VA_ARGS__))
#define KJ_FAIL_REQUIRE(...) KJ_EXPAND(_kJ_FAIL_FAULT(PRECONDITION, __VA_ARGS__))
#define KJ_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
for (::kj::_::Debug::Fault f( \
__FILE__, __LINE__, ::kj::Exception::Nature::OS_ERROR, \
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_NONBLOCKING_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
for (::kj::_::Debug::Fault f( \
__FILE__, __LINE__, ::kj::Exception::Nature::OS_ERROR, \
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f( \
__FILE__, __LINE__, ::kj::Exception::Nature::OS_ERROR, \
errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_CONTEXT(...) \
auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
::kj::_::Debug::makeContextDescription("" #__VA_ARGS__, __VA_ARGS__)); \
}; \
::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))> \
KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
#define _kJ_NONNULL(nature, value, ...) \
(*({ \
auto _kj_result = ::kj::_::readMaybe(value); \
if (KJ_UNLIKELY(!_kj_result)) { \
::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Nature::nature, 0, \
#value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \
} \
_kj_result; \
}))
#define KJ_ASSERT_NONNULL(value, ...) KJ_EXPAND(_kJ_NONNULL(LOCAL_BUG, value, __VA_ARGS__))
#define KJ_REQUIRE_NONNULL(value, ...) KJ_EXPAND(_kJ_NONNULL(PRECONDITION, value, __VA_ARGS__))
#else
#define KJ_LOG(severity, ...) \ #define KJ_LOG(severity, ...) \
if (!::kj::_::Debug::shouldLog(::kj::_::Debug::Severity::severity)) {} else \ if (!::kj::_::Debug::shouldLog(::kj::_::Debug::Severity::severity)) {} else \
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::_::Debug::Severity::severity, \ ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::_::Debug::Severity::severity, \
...@@ -180,6 +255,8 @@ namespace kj { ...@@ -180,6 +255,8 @@ namespace kj {
#define KJ_ASSERT_NONNULL(value, ...) _kJ_NONNULL(LOCAL_BUG, value, ##__VA_ARGS__) #define KJ_ASSERT_NONNULL(value, ...) _kJ_NONNULL(LOCAL_BUG, value, ##__VA_ARGS__)
#define KJ_REQUIRE_NONNULL(value, ...) _kJ_NONNULL(PRECONDITION, value, ##__VA_ARGS__) #define KJ_REQUIRE_NONNULL(value, ...) _kJ_NONNULL(PRECONDITION, value, ##__VA_ARGS__)
#endif
#ifdef KJ_DEBUG #ifdef KJ_DEBUG
#define KJ_DLOG LOG #define KJ_DLOG LOG
#define KJ_DASSERT KJ_ASSERT #define KJ_DASSERT KJ_ASSERT
...@@ -225,6 +302,8 @@ public: ...@@ -225,6 +302,8 @@ public:
template <typename... Params> template <typename... Params>
Fault(const char* file, int line, Exception::Nature nature, int errorNumber, Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs, Params&&... params); const char* condition, const char* macroArgs, Params&&... params);
Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs);
~Fault() noexcept(false); ~Fault() noexcept(false);
KJ_NORETURN(void fatal()); KJ_NORETURN(void fatal());
...@@ -314,6 +393,11 @@ void Debug::log(const char* file, int line, Severity severity, const char* macro ...@@ -314,6 +393,11 @@ void Debug::log(const char* file, int line, Severity severity, const char* macro
logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params))); logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params)));
} }
template <>
inline void Debug::log<>(const char* file, int line, Severity severity, const char* macroArgs) {
logInternal(file, line, severity, macroArgs, nullptr);
}
template <typename... Params> template <typename... Params>
Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int errorNumber, Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs, Params&&... params) const char* condition, const char* macroArgs, Params&&... params)
...@@ -323,6 +407,12 @@ Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int er ...@@ -323,6 +407,12 @@ Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int er
arrayPtr(argValues, sizeof...(Params))); arrayPtr(argValues, sizeof...(Params)));
} }
inline Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs)
: exception(nullptr) {
init(file, line, nature, errorNumber, condition, macroArgs, nullptr);
}
template <typename Call> template <typename Call>
Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) { Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
while (call() < 0) { while (call() < 0) {
...@@ -343,6 +433,11 @@ String Debug::makeContextDescription(const char* macroArgs, Params&&... params) ...@@ -343,6 +433,11 @@ String Debug::makeContextDescription(const char* macroArgs, Params&&... params)
return makeContextDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params))); return makeContextDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params)));
} }
template <>
inline String Debug::makeContextDescription<>(const char* macroArgs) {
return makeContextDescriptionInternal(macroArgs, nullptr);
}
} // namespace _ (private) } // namespace _ (private)
} // namespace kj } // namespace kj
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "string.h" #include "string.h"
#include "debug.h" #include "debug.h"
#include "threadlocal.h" #include "threadlocal.h"
#include <unistd.h> #include "miniposix.h"
#include <stdlib.h> #include <stdlib.h>
#include <exception> #include <exception>
...@@ -317,7 +317,7 @@ public: ...@@ -317,7 +317,7 @@ public:
StringPtr textPtr = text; StringPtr textPtr = text;
while (text != nullptr) { while (text != nullptr) {
ssize_t n = write(STDERR_FILENO, textPtr.begin(), textPtr.size()); miniposix::ssize_t n = miniposix::write(STDERR_FILENO, textPtr.begin(), textPtr.size());
if (n <= 0) { if (n <= 0) {
// stderr is broken. Give up. // stderr is broken. Give up.
return; return;
...@@ -397,6 +397,26 @@ uint uncaughtExceptionCount() { ...@@ -397,6 +397,26 @@ uint uncaughtExceptionCount() {
return __cxa_get_globals()->uncaughtExceptions; return __cxa_get_globals()->uncaughtExceptions;
} }
#elif _MSC_VER
#if 0
// TODO(msvc): The below was copied from:
// https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
// Alas, it doesn not appera to work on MSVC2015. The linker claims _getptd() doesn't exist.
extern "C" char *__cdecl _getptd();
uint uncaughtExceptionCount() {
return *reinterpret_cast<uint*>(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90));
}
#endif
uint uncaughtExceptionCount() {
// Since the above doesn't work, fall back to uncaught_exception(). This will produce incorrect
// results in very obscure cases that Cap'n Proto doesn't really rely on anyway.
return std::uncaught_exception();
}
#else #else
#error "This needs to be ported to your compiler / C++ ABI." #error "This needs to be ported to your compiler / C++ ABI."
#endif #endif
......
...@@ -21,14 +21,8 @@ ...@@ -21,14 +21,8 @@
#include "io.h" #include "io.h"
#include "debug.h" #include "debug.h"
#include "miniposix.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <unistd.h>
#if _WIN32
#include <io.h>
#include <fcntl.h>
#define pipe(fds) _pipe(fds, 8192, _O_BINARY)
#endif
namespace kj { namespace kj {
namespace { namespace {
...@@ -38,7 +32,7 @@ TEST(Io, WriteVec) { ...@@ -38,7 +32,7 @@ TEST(Io, WriteVec) {
// used to not work in some cases.) // used to not work in some cases.)
int fds[2]; int fds[2];
KJ_SYSCALL(pipe(fds)); KJ_SYSCALL(miniposix::pipe(fds));
FdInputStream in((AutoCloseFd(fds[0]))); FdInputStream in((AutoCloseFd(fds[0])));
FdOutputStream out((AutoCloseFd(fds[1]))); FdOutputStream out((AutoCloseFd(fds[1])));
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "io.h" #include "io.h"
#include "debug.h" #include "debug.h"
#include <unistd.h> #include "miniposix.h"
#include <algorithm> #include <algorithm>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
...@@ -238,7 +238,7 @@ AutoCloseFd::~AutoCloseFd() noexcept(false) { ...@@ -238,7 +238,7 @@ AutoCloseFd::~AutoCloseFd() noexcept(false) {
if (fd >= 0) { if (fd >= 0) {
unwindDetector.catchExceptionsIfUnwinding([&]() { unwindDetector.catchExceptionsIfUnwinding([&]() {
// Don't use SYSCALL() here because close() should not be repeated on EINTR. // Don't use SYSCALL() here because close() should not be repeated on EINTR.
if (close(fd) < 0) { if (miniposix::close(fd) < 0) {
KJ_FAIL_SYSCALL("close", errno, fd) { KJ_FAIL_SYSCALL("close", errno, fd) {
break; break;
} }
...@@ -255,8 +255,8 @@ size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) { ...@@ -255,8 +255,8 @@ size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) {
byte* max = pos + maxBytes; byte* max = pos + maxBytes;
while (pos < min) { while (pos < min) {
ssize_t n; miniposix::ssize_t n;
KJ_SYSCALL(n = ::read(fd, pos, max - pos), fd); KJ_SYSCALL(n = miniposix::read(fd, pos, max - pos), fd);
if (n == 0) { if (n == 0) {
break; break;
} }
...@@ -272,8 +272,8 @@ void FdOutputStream::write(const void* buffer, size_t size) { ...@@ -272,8 +272,8 @@ void FdOutputStream::write(const void* buffer, size_t size) {
const char* pos = reinterpret_cast<const char*>(buffer); const char* pos = reinterpret_cast<const char*>(buffer);
while (size > 0) { while (size > 0) {
ssize_t n; miniposix::ssize_t n;
KJ_SYSCALL(n = ::write(fd, pos, size), fd); KJ_SYSCALL(n = miniposix::write(fd, pos, size), fd);
KJ_ASSERT(n > 0, "write() returned zero."); KJ_ASSERT(n > 0, "write() returned zero.");
pos += n; pos += n;
size -= n; size -= n;
......
...@@ -38,7 +38,7 @@ TEST(Memory, OwnConst) { ...@@ -38,7 +38,7 @@ TEST(Memory, OwnConst) {
} }
TEST(Memory, CanConvert) { TEST(Memory, CanConvert) {
struct Super { virtual ~Super(); }; struct Super { virtual ~Super() {} };
struct Sub: public Super {}; struct Sub: public Super {};
static_assert(canConvert<Own<Sub>, Own<Super>>(), "failure"); static_assert(canConvert<Own<Sub>, Own<Super>>(), "failure");
......
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_PORTABLE_FD_H_
#define KJ_PORTABLE_FD_H_
// This header provides a small subset of the POSIX API which also happens to be available on
// Windows under slightly-different names.
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#if _WIN32
#include <io.h>
#include <direct.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
namespace kj {
namespace miniposix {
#if _WIN32 && !__GNUC__
// We're on Windows and not MinGW. So, we need to define wrappers for the POSIX API.
typedef int ssize_t;
inline ssize_t read(int fd, void* buffer, size_t size) {
return ::_read(fd, buffer, size);
}
inline ssize_t write(int fd, const void* buffer, size_t size) {
return ::_write(fd, buffer, size);
}
inline int close(int fd) {
return ::_close(fd);
}
inline int pipe(int fds[2]) {
return ::_pipe(fds, 4096, false);
}
inline int mkdir(const char* path, int mode) {
return ::_mkdir(path);
}
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#else
// We're on a POSIX system or MinGW which already defines the wrappers for us.
using ::ssize_t;
using ::read;
using ::write;
using ::close;
using ::pipe;
using ::mkdir;
#endif
} // namespace miniposix
} // namespace kj
#endif // KJ_WIN32_FD_H_
...@@ -28,6 +28,11 @@ ...@@ -28,6 +28,11 @@
namespace kj { namespace kj {
#if _MSC_VER
#pragma warning(disable: 4996)
// Warns that sprintf() is buffer-overrunny. We know that, it's cool.
#endif
String heapString(size_t size) { String heapString(size_t size) {
char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1); char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1);
buffer[size] = '\0'; buffer[size] = '\0';
...@@ -256,11 +261,11 @@ char* DoubleToBuffer(double value, char* buffer) { ...@@ -256,11 +261,11 @@ char* DoubleToBuffer(double value, char* buffer) {
// truncated to a double. // truncated to a double.
volatile double parsed_value = strtod(buffer, NULL); volatile double parsed_value = strtod(buffer, NULL);
if (parsed_value != value) { if (parsed_value != value) {
int snprintf_result = int snprintf_result2 =
snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value); snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value);
// Should never overflow; see above. // Should never overflow; see above.
KJ_DASSERT(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize); KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kDoubleToBufferSize);
} }
DelocalizeRadix(buffer); DelocalizeRadix(buffer);
...@@ -275,7 +280,7 @@ bool safe_strtof(const char* str, float* value) { ...@@ -275,7 +280,7 @@ bool safe_strtof(const char* str, float* value) {
char* endptr; char* endptr;
errno = 0; // errno only gets set on errors errno = 0; // errno only gets set on errors
#if defined(_WIN32) || defined (__hpux) // has no strtof() #if defined(_WIN32) || defined (__hpux) // has no strtof()
*value = strtod(str, &endptr); *value = static_cast<float>(strtod(str, &endptr));
#else #else
*value = strtof(str, &endptr); *value = strtof(str, &endptr);
#endif #endif
...@@ -309,11 +314,11 @@ char* FloatToBuffer(float value, char* buffer) { ...@@ -309,11 +314,11 @@ char* FloatToBuffer(float value, char* buffer) {
float parsed_value; float parsed_value;
if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) { if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) {
int snprintf_result = int snprintf_result2 =
snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value); snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value);
// Should never overflow; see above. // Should never overflow; see above.
KJ_DASSERT(snprintf_result > 0 && snprintf_result < kFloatToBufferSize); KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kFloatToBufferSize);
} }
DelocalizeRadix(buffer); DelocalizeRadix(buffer);
......
...@@ -300,7 +300,7 @@ struct Stringifier { ...@@ -300,7 +300,7 @@ struct Stringifier {
inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); } inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); }
#endif #endif
}; };
static constexpr Stringifier STR = Stringifier(); static KJ_CONSTEXPR(const) Stringifier STR = Stringifier();
} // namespace _ (private) } // namespace _ (private)
......
...@@ -120,10 +120,14 @@ private: ...@@ -120,10 +120,14 @@ private:
} // namespace _ (private) } // namespace _ (private)
#else #elif __GNUC__
#define KJ_THREADLOCAL_PTR(type) static __thread type* #define KJ_THREADLOCAL_PTR(type) static __thread type*
// For // GCC's __thread is lighter-weight than thread_local and is good enough for our purposes.
#else
#define KJ_THREADLOCAL_PTR(type) static thread_local type*
#endif // KJ_USE_PTHREAD_TLS #endif // KJ_USE_PTHREAD_TLS
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment