fix Issue 16291 - EncodingScheme.create fails

- add EncodingScheme.register overload that references the registered class
- just adding the FQN name of a class does not reference that class, so
  it must not end up in the binary and subsequently EncodingScheme.create failed
- This used to work by chance b/c all the EncodingScheme implementations
  were in a module w/ static ctor. Any user of std.encoding did drag in
  that ModuleInfo, which in turn referenced all classes of std.encoding.
  Since moving the static ctor to std.internal.phobosinit to break a
  cycle, the classes were no longer referenced by a ModuleInfo w/ shared
  ctor, so they wouldn't end up in the binary unless explicitly
  referenced elsewhere.
- deprecate the old EncodingScheme.register(string fqn) b/c relying on
  Object.factory is slow, error prone (linkage), and really unnecessary
- import encodinginit in std.encoding so that the
  std_encoding_shared_static_this callback actually gets run
This commit is contained in:
Martin Nowak 2016-10-05 00:40:39 +02:00
parent ebbdf21a7e
commit 9d73d18c0c
6 changed files with 60 additions and 32 deletions

View file

@ -216,7 +216,7 @@ EXTRA_MODULES_INTERNAL := $(addprefix \
std/internal/digest/, sha_SSSE3 ) $(addprefix \
std/internal/math/, biguintcore biguintnoasm biguintx86 \
gammafunction errorfunction) $(addprefix std/internal/, \
cstring phobosinit processinit unicode_tables scopebuffer\
cstring encodinginit processinit unicode_tables scopebuffer\
unicode_comp unicode_decomp unicode_grapheme unicode_norm) \
$(addprefix std/internal/test/, dummyrange) \
$(addprefix std/experimental/ndslice/, internal) \

View file

@ -55,6 +55,7 @@ module std.encoding;
import std.traits;
import std.typecons;
import std.range.primitives;
import std.internal.encodinginit;
@system unittest
{
@ -2360,17 +2361,30 @@ abstract class EncodingScheme
* This function allows user-defined subclasses of EncodingScheme to
* be declared in other modules.
*
* Params:
* Klass = The subclass of EncodingScheme to register.
*
* Example:
* ----------------------------------------------
* class Amiga1251 : EncodingScheme
* {
* shared static this()
* {
* EncodingScheme.register("path.to.Amiga1251");
* EncodingScheme.register!Amiga1251;
* }
* }
* ----------------------------------------------
*/
static void register(Klass:EncodingScheme)()
{
scope scheme = new Klass();
foreach (encodingName;scheme.names())
{
supported[toLower(encodingName)] = () => new Klass();
}
}
deprecated("Please pass the EncodingScheme subclass as template argument instead.")
static void register(string className)
{
auto scheme = cast(EncodingScheme)ClassInfo.find(className).create();
@ -2378,7 +2392,7 @@ abstract class EncodingScheme
throw new EncodingException("Unable to create class "~className);
foreach (encodingName;scheme.names())
{
supported[toLower(encodingName)] = className;
supportedFactories[toLower(encodingName)] = className;
}
}
@ -2396,7 +2410,12 @@ abstract class EncodingScheme
*/
static EncodingScheme create(string encodingName)
{
auto p = toLower(encodingName) in supported;
encodingName = toLower(encodingName);
if (auto p = encodingName in supported)
return (*p)();
auto p = encodingName in supportedFactories;
if (p is null)
throw new EncodingException("Unrecognized Encoding: "~encodingName);
string className = *p;
@ -2650,7 +2669,8 @@ abstract class EncodingScheme
return t.length - s.length;
}
__gshared string[string] supported;
__gshared EncodingScheme function()[string] supported;
__gshared string[string] supportedFactories;
}
/**
@ -3297,6 +3317,20 @@ class EncodingSchemeUtf32Native : EncodingScheme
assert(ub.length == 8);
}
// shared static this() called from encodinginit to break ctor cycle
extern(C) void std_encoding_shared_static_this()
{
EncodingScheme.register!EncodingSchemeASCII;
EncodingScheme.register!EncodingSchemeLatin1;
EncodingScheme.register!EncodingSchemeLatin2;
EncodingScheme.register!EncodingSchemeWindows1250;
EncodingScheme.register!EncodingSchemeWindows1252;
EncodingScheme.register!EncodingSchemeUtf8;
EncodingScheme.register!EncodingSchemeUtf16Native;
EncodingScheme.register!EncodingSchemeUtf32Native;
}
//=============================================================================

View file

@ -0,0 +1,19 @@
// Written in the D programming language.
/++
The purpose of this module is to perform static construction away from the
normal modules to eliminate cyclic construction errors.
Copyright: Copyright 2011 - 2016
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: Martin Nowak, Steven Schveighoffer
Source: $(PHOBOSSRC std/internal/_encodinginit.d)
+/
module std.internal.encodinginit;
extern(C) void std_encoding_shared_static_this();
shared static this()
{
std_encoding_shared_static_this();
}

View file

@ -1,25 +0,0 @@
// Written in the D programming language.
/++
The purpose of this module is to perform static construction away from the
normal modules to eliminate cyclic construction errors.
Copyright: Copyright 2011 - 2016
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: Jonathan M Davis, Kato Shoichi, Steven Schveighoffer
Source: $(PHOBOSSRC std/internal/_phobosinit.d)
+/
module std.internal.phobosinit;
shared static this()
{
import std.encoding : EncodingScheme;
EncodingScheme.register("std.encoding.EncodingSchemeASCII");
EncodingScheme.register("std.encoding.EncodingSchemeLatin1");
EncodingScheme.register("std.encoding.EncodingSchemeLatin2");
EncodingScheme.register("std.encoding.EncodingSchemeWindows1250");
EncodingScheme.register("std.encoding.EncodingSchemeWindows1252");
EncodingScheme.register("std.encoding.EncodingSchemeUtf8");
EncodingScheme.register("std.encoding.EncodingSchemeUtf16Native");
EncodingScheme.register("std.encoding.EncodingSchemeUtf32Native");
}

View file

@ -267,7 +267,7 @@ SRC_STD_C_FREEBSD= \
SRC_STD_INTERNAL= \
std\internal\cstring.d \
std\internal\phobosinit.d \
std\internal\encodinginit.d \
std\internal\processinit.d \
std\internal\unicode_tables.d \
std\internal\unicode_comp.d \

View file

@ -286,7 +286,7 @@ SRC_STD_C_FREEBSD= \
SRC_STD_INTERNAL= \
std\internal\cstring.d \
std\internal\phobosinit.d \
std\internal\encodinginit.d \
std\internal\processinit.d \
std\internal\unicode_tables.d \
std\internal\unicode_comp.d \