(#15398) fix typo in Scope#number? float detection regex

This allowed incorrect numbers (like 2:.34) to be recognized as
floats (with an incorrect value).

Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
Don't allow resource titles which aren't strings

It was possible to create resources whose titles weren't strings, by
using a variable containing a hash, or the result of a function which
doesn't return a string. This can cause problems resolving relationships
when the stringified version of the title differs between master and
agent.

Now we will only accept primitives, and will stringify them. That is:
string, symbol, number, boolean. Arrays or nested arrays will still be
flattened and used to create multiple resources. Any other value (for
instance: a hash) will cause a parse error.
Implement Symbol#intern when it is missing.

In order to reduce use of `Puppet::Util#symbolize` in the code - which is
called some 90,000 times in a real-world run - being able to intern a symbol
is convenient.

This is a simple implementation: it just returns itself.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Use `intern` rather than `symbolize` in Puppet::Type

The cost of symbolize is ~ 50 percent higher than the cost of intern, when
applied to either a string or a symbol.  Given this is called some 90,000
times in my real world test run, that adds up to a non-zero amount of
wasted time.

Sadly, this only works out at 0.15 seconds real time reduction, but it is
better than nothing - and takes out 85,000 extra calls.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Eliminate `symbolize` everywhere, and remove it.

The whole `symbolize` API was confusing and complex: because it didn't do any
type enforcement, just passed through arbitrary data, we had very unclear API
in a whole pile of places.

This replaces that method entirely with a more rigid definition: we intern in
a bunch of places, add the occasional clear failure mode, and then delete the
original definition.

This eliminates one point of complexity from the codebase.

(These other uses have no notable performance penalty, just code complexity
 and clarity issues.)

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
zaml: statically determine the to_ascii8bit implementation.

Instead of asking every single string the same question, "do you respond to
`encoding`", we can just figure that out once and choose an implementation
based on the result - since it is a static test on the same class every time.

This saves ~ 0.1 second of runtime, which is small but cheap.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
zaml: rework strings for correctness and speed

This changes the implementation of string output in the ZAML encoder.  On my
test that delivers around a fifty percent reduction in output time, from 4.11
to 1.89 seconds on my test of ~ 35,000 output strings.

It also adds a bunch of tests to validate the correctness of binary output
handling, and some test inputs derived from various security related UTF-8
encoding problems to validate that (sadly) we pass them through as
binary data.

Optimally we would treat binary and text input as distinct in the parser and
compiler of Puppet, then only allow legal UTF-8 in strings - but that is not
the world in which we live.

It finally fixes a bug in the binary output along the way - which, thankfully,
nobody actually seems to have run into since I introduced it in ea0dd1483fc2.

Because the Ruby BASE64 encoder will split lines at the 60 character mark, a
long binary input would end up with embedded newlines in places that were not
legal for YAML.

Instead of just emitting that, we run through the string encoder over the
transformed data, which leads to a solid output format that works entirely
as expected.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
zaml: add whitespace for readability.

The ZAML code has very little whitespace, leading to a difficult to read set
of code.  This just adds a little whitespace, with no behaviour change, to
improve that before I start hacking directly on that code.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
zaml: avoid calling emit when we don't have anything to output

The `nl` method allowed an additional string to be output after the newline;
this is seldom used, and the default implementation resulted in emitting an
empty string.

We can just skip that, for a minor win in function call count.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
zaml: don't use backreferences on strings

While the YAML spec requires that we emit a backreference if the same string
object occurs twice in our content, it also costs a lot.  About two seconds of
time encoding the output, in my testing, out of a total of three.

Everything we do internally with YAML doesn't actually *depend* on the ability
to serialize an object graph that treats String objects as duplicated.

This is reinforced by every object that can serialize to PSON - since
it *can't* have a back-reference, you automatically get string duplication
there.

That means that we can just cut those few seconds out of the code without any
particular cost or suffering, and shave *way* more time off a run than almost
anything else we can do to our YAML output code.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Eliminate Puppet type attribute aliases.

About six years back we added attribute aliases to the Puppet type definition.
Although it isn't completely clear why this was done, it wasn't used then, and
hasn't been used over the last six years or so.

Since this has a non-trivial cost checking for an alias every single time we
touch a property, and we do that ... a lot, eliminating the code has a small
but notable reduction in CPU time.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
zaml: unify on a single definition of `to_zaml` for Symbol

There were two competitive definitions of the `to_zaml` function over Symbol,
one in monkey_patches and one in the core ZAML library.

The monkey patch version won in practice, so now they are unified, and the
monkey patch version is adopted to replace the core ZAML version, in the zaml
Ruby file.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Avoid object creation/destruction when possible.

Object creation and destruction, even over a short time-frame, is expensive,
so where we can avoid it we should.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
type: memoize key_attributes for types.

The key_attributes have about a 0.05 percent miss rate on the cache, and the
value is static for the life of the type, so we can avoid substantial numbers
of object allocations.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
Merge pull request #943 from joshcooper/maint/2.7.x/openrc-spec

(Maint) Don't assume paths are absolute
tagging: document why fixing this horror is hard.

The tagging support module has an "API" that includes other objects directly
interacting with the way it stores data, including at the edges where we
serialize to the wire format for transport.

So, we can't change it.  Even if it sucks - it allocates lots of objects, it
uses very inefficient deduplication mechanisms - we are kind of stuck,
right now.  Fun times.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
lexer: remove some unused stats collection

The lexer was instrumented to identify the number of regex vs string tokens
matched in the system - presumably as part of making sure it was testing in
the optimal order.

At this point we know the outcomes, so the collection can be removed.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
monkey_patch: cache Symbol to_proc result.

If we use it, our monkey-patch version of Symbol to_proc is worth caching the
resulting proc - the hit rate is through the roof, because we only really act
on a small set of symbols.

This reduces some extra object and memory allocation by reusing the same proc
every time we transform the same symbol.

That saves 99.84 percent of the memory allocated from this method - about four
percent of the total memory allocation in my test run of Puppet with real
manifests and behaviours.  (About 10MB out of 260MB originally; 26kb after.)

This applies to all versions - newer Rubies with a real implementation of
to_proc don't cache the result, so we do it for them.

Older versions *cough* 1.8.5 *cough* still get our hand-written implementation
of the proc, so that they work. It probably is equivalent to the real version,
but I would rather allow core changes to show.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
type: support implicit "identity" transformation

Almost every implementation of `title_patterns` on a type returned with a
lambda that performed an "identity" transformation - `lambda {|x| x }`.

That actually cost a notable amount of memory allocation, because it created a
new instance of the lambda on every invocation. That represented about three
percent of total memory allocation, or 8MB total.

This allows the `title_patterns` data to simply omit the lambda - if you don't
supply one, we don't invoke it to transform the result, just assign directly.

This allows everyone to keep using this the way they currently do, including
supplying an identity lambda if they want, but allows internal types and types
that don't override the default to be more memory efficient.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>
FileCollection is a memory loss, not a memory win.

The file type used the FileCollection object to try and reduce memory
consumption by deduplicating path strings.

Unfortunately, this had the opposite effect in the real world, even when many
duplicate paths were present - it cost about 1.5MB extra memory in my tests.

It also costs non-trivial CPU time reconstituting the original path every time
we need to interact with that, and we do that a bunch.

So, just ditch the entire thing and move folks to just using paths directly.

Signed-off-by: Daniel Pittman <daniel@puppetlabs.com>