From 0db187e7aef746c7abd079110172508598d9b672 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:20:30 +0000 Subject: [PATCH] Deploy to GitHub pages --- .circleci/config.yml | 33 + .circleci/run.sh | 105 ++ index.html | 35 + lu.array.html | 42 + lu.array.uniqueKey.html | 66 + lu.common.FileExistsException.filename.html | 35 + lu.common.FileExistsException.html | 36 + lu.common.FileExistsException.this.1.html | 35 + lu.common.FileExistsException.this.2.html | 35 + lu.common.FileExistsException.this.html | 1 + ...ommon.FileTypeMismatchException.attrs.html | 35 + ...on.FileTypeMismatchException.filename.html | 35 + lu.common.FileTypeMismatchException.html | 38 + ...mmon.FileTypeMismatchException.this.1.html | 35 + ...mmon.FileTypeMismatchException.this.2.html | 35 + lu.common.FileTypeMismatchException.this.html | 1 + lu.common.Next.html | 35 + lu.common.ReturnValueException.command.html | 35 + lu.common.ReturnValueException.html | 36 + lu.common.ReturnValueException.retval.html | 35 + lu.common.ReturnValueException.this.1.html | 35 + lu.common.ReturnValueException.this.2.html | 35 + lu.common.ReturnValueException.this.3.html | 35 + lu.common.ReturnValueException.this.html | 1 + lu.common.html | 37 + lu.common.sharedDomains.html | 86 + lu.container.Buffer.buf.1.html | 35 + lu.container.Buffer.buf.2.html | 35 + lu.container.Buffer.buf.html | 1 + lu.container.Buffer.bufferSize.1.html | 35 + lu.container.Buffer.bufferSize.2.html | 35 + lu.container.Buffer.bufferSize.html | 1 + lu.container.Buffer.clear.html | 35 + lu.container.Buffer.empty.html | 37 + lu.container.Buffer.end.html | 35 + lu.container.Buffer.front.html | 35 + lu.container.Buffer.growthFactor.html | 35 + lu.container.Buffer.html | 152 ++ lu.container.Buffer.length.html | 36 + lu.container.Buffer.opOpAssign.html | 35 + lu.container.Buffer.popFront.html | 35 + lu.container.Buffer.pos.html | 35 + lu.container.Buffer.put.1.html | 35 + lu.container.Buffer.put.2.html | 35 + lu.container.Buffer.put.html | 1 + lu.container.Buffer.reserve.html | 36 + lu.container.Buffer.reset.html | 36 + lu.container.CircularBuffer.buf.1.html | 35 + lu.container.CircularBuffer.buf.2.html | 35 + lu.container.CircularBuffer.buf.html | 1 + lu.container.CircularBuffer.caughtUp.html | 36 + lu.container.CircularBuffer.clear.html | 35 + lu.container.CircularBuffer.dup.html | 35 + lu.container.CircularBuffer.empty.html | 37 + lu.container.CircularBuffer.front.html | 35 + lu.container.CircularBuffer.head.html | 35 + lu.container.CircularBuffer.html | 137 ++ lu.container.CircularBuffer.initialised.html | 35 + lu.container.CircularBuffer.opOpAssign.html | 35 + lu.container.CircularBuffer.popFront.html | 35 + lu.container.CircularBuffer.put.html | 36 + lu.container.CircularBuffer.reset.html | 35 + lu.container.CircularBuffer.resize.html | 35 + lu.container.CircularBuffer.save.html | 35 + lu.container.CircularBuffer.size.html | 35 + lu.container.CircularBuffer.tail.html | 35 + lu.container.MutexedAA.aa.html | 35 + lu.container.MutexedAA.clear.html | 43 + lu.container.MutexedAA.get.html | 47 + lu.container.MutexedAA.has.html | 39 + lu.container.MutexedAA.html | 309 ++++ lu.container.MutexedAA.isReady.html | 36 + lu.container.MutexedAA.keys.html | 43 + lu.container.MutexedAA.length.html | 41 + lu.container.MutexedAA.mutex.html | 35 + lu.container.MutexedAA.opEquals.1.html | 50 + lu.container.MutexedAA.opEquals.2.html | 47 + lu.container.MutexedAA.opEquals.html | 1 + lu.container.MutexedAA.opIndex.html | 41 + lu.container.MutexedAA.opIndexAssign.html | 39 + lu.container.MutexedAA.opIndexOpAssign.html | 43 + lu.container.MutexedAA.opIndexUnary.html | 39 + lu.container.MutexedAA.rehash.html | 40 + lu.container.MutexedAA.remove.html | 42 + lu.container.MutexedAA.require.html | 41 + lu.container.MutexedAA.setup.html | 36 + lu.container.MutexedAA.uniqueKey.html | 44 + lu.container.MutexedAA.update.html | 50 + lu.container.MutexedAA.values.html | 43 + ...ainer.RehashingAA._lengthAtLastRehash.html | 36 + ...r.RehashingAA._newKeysSinceLastRehash.html | 35 + lu.container.RehashingAA._numRehashes.html | 35 + lu.container.RehashingAA.aa.html | 35 + lu.container.RehashingAA.aaOf.html | 35 + lu.container.RehashingAA.clear.html | 35 + lu.container.RehashingAA.dup.html | 35 + lu.container.RehashingAA.html | 68 + lu.container.RehashingAA.length.html | 35 + lu.container.RehashingAA.maybeRehash.html | 36 + ...er.RehashingAA.minimumNeededForRehash.html | 35 + ...er.RehashingAA.newKeysSinceLastRehash.html | 35 + lu.container.RehashingAA.numRehashes.html | 35 + lu.container.RehashingAA.onRehashDg.html | 35 + lu.container.RehashingAA.opAssign.html | 35 + lu.container.RehashingAA.opBinaryRight.html | 36 + lu.container.RehashingAA.opCast.html | 35 + lu.container.RehashingAA.opIndexAssign.html | 36 + lu.container.RehashingAA.rehash.html | 36 + ...RehashingAA.rehashThresholdMultiplier.html | 37 + lu.container.RehashingAA.remove.html | 36 + lu.container.RehashingAA.this.html | 35 + lu.container.html | 128 ++ lu.conv.Enum.fromString.html | 48 + lu.conv.Enum.html | 63 + lu.conv.Enum.toString.html | 42 + lu.conv.enumToString.html | 48 + lu.conv.html | 46 + lu.conv.numFromHex.html | 36 + lu.conv.rgbFromHex.html | 66 + lu.conv.toAlpha.html | 79 + lu.conv.toAlphaInto.html | 92 + lu.deltastrings.formatDeltaInto.html | 223 +++ lu.deltastrings.html | 82 + lu.html | 45 + lu.json.JSONStorage.KeyOrderStrategy.html | 38 + lu.json.JSONStorage.html | 63 + lu.json.JSONStorage.load.html | 39 + lu.json.JSONStorage.reset.html | 36 + lu.json.JSONStorage.save.html | 38 + lu.json.JSONStorage.serialiseInto.1.html | 38 + lu.json.JSONStorage.serialiseInto.2.html | 138 ++ lu.json.JSONStorage.serialiseInto.html | 1 + lu.json.JSONStorage.storage.html | 35 + lu.json.html | 76 + lu.json.populateFromJSON.html | 161 ++ lu.meld.MeldingStrategy.html | 39 + lu.meld.Unmeldable.html | 35 + lu.meld.html | 69 + lu.meld.meldInto.1.html | 352 ++++ lu.meld.meldInto.2.html | 71 + lu.meld.meldInto.3.html | 76 + lu.meld.meldInto.html | 1 + lu.numeric.getMultipleOf.html | 68 + lu.numeric.html | 39 + lu.objmanip.SetMemberException.html | 36 + ...jmanip.SetMemberException.memberToSet.html | 35 + lu.objmanip.SetMemberException.this.1.html | 35 + lu.objmanip.SetMemberException.this.2.html | 35 + lu.objmanip.SetMemberException.this.html | 1 + lu.objmanip.SetMemberException.typeName.html | 35 + ...bjmanip.SetMemberException.valueToSet.html | 35 + lu.objmanip.html | 64 + lu.objmanip.pruneAA.html | 118 ++ lu.objmanip.replaceMembers.html | 119 ++ lu.objmanip.setMemberByName.1.html | 239 +++ lu.objmanip.setMemberByName.2.html | 80 + lu.objmanip.setMemberByName.html | 1 + lu.semver.LuSemVer.html | 35 + lu.semver.LuSemVerPrerelease.html | 35 + lu.semver.html | 36 + ...erialisation.DeserialisationException.html | 36 + ...isation.DeserialisationException.this.html | 35 + ...sation.SerialisationUDAs.arrayPattern.html | 36 + ...on.SerialisationUDAs.escapedSeparator.html | 35 + lu.serialisation.SerialisationUDAs.html | 37 + ...alisation.SerialisationUDAs.separator.html | 35 + ...tion.SerialisationUDAs.unserialisable.html | 35 + lu.serialisation.deserialise.html | 290 +++ lu.serialisation.html | 90 + lu.serialisation.justifiedEntryValueText.html | 142 ++ lu.serialisation.serialise.1.html | 52 + lu.serialisation.serialise.2.html | 162 ++ lu.serialisation.serialise.html | 1 + lu.serialisation.serialiseArrayImpl.html | 38 + lu.serialisation.splitEntryValue.html | 64 + lu.string.AdvanceException.haystack.html | 35 + lu.string.AdvanceException.html | 35 + lu.string.AdvanceException.needle.html | 35 + lu.string.AdvanceException.this.html | 35 + lu.string.AdvanceExceptionImpl._haystack.html | 35 + lu.string.AdvanceExceptionImpl._needle.html | 35 + lu.string.AdvanceExceptionImpl.haystack.html | 35 + lu.string.AdvanceExceptionImpl.html | 36 + lu.string.AdvanceExceptionImpl.needle.html | 35 + lu.string.AdvanceExceptionImpl.this.1.html | 35 + lu.string.AdvanceExceptionImpl.this.2.html | 35 + lu.string.AdvanceExceptionImpl.this.html | 1 + lu.string.NomException.html | 35 + lu.string.NomExceptionImpl.html | 35 + lu.string.SplitResults.html | 35 + lu.string.advancePast.1.html | 238 +++ lu.string.advancePast.2.html | 38 + lu.string.advancePast.html | 1 + lu.string.beginsWithOneOf.html | 52 + lu.string.decode64.html | 45 + lu.string.encode64.html | 45 + lu.string.escapeControlCharacters.html | 62 + lu.string.html | 83 + lu.string.indent.html | 73 + lu.string.indentInto.html | 70 + lu.string.nom.html | 35 + lu.string.plurality.html | 47 + lu.string.removeControlCharacters.html | 60 + lu.string.splitInto.1.html | 107 ++ lu.string.splitInto.2.html | 181 ++ lu.string.splitInto.html | 1 + lu.string.splitLineAtPosition.html | 87 + lu.string.splitWithQuotes.html | 123 ++ lu.string.stripSuffix.html | 41 + lu.string.stripped.1.html | 69 + lu.string.stripped.2.html | 88 + lu.string.stripped.html | 1 + lu.string.strippedLeft.1.html | 67 + lu.string.strippedLeft.2.html | 77 + lu.string.strippedLeft.html | 1 + lu.string.strippedRight.1.html | 67 + lu.string.strippedRight.2.html | 77 + lu.string.strippedRight.html | 1 + lu.string.tabs.html | 59 + lu.string.unenclosed.html | 37 + lu.string.unquoted.html | 44 + lu.string.unsinglequoted.html | 44 + lu.traits.CategoryName.fqn.html | 35 + lu.traits.CategoryName.html | 101 ++ lu.traits.CategoryName.name.html | 35 + lu.traits.MixinConstraints.html | 89 + lu.traits.MixinScope.html | 35 + lu.traits.TakesParams.1.html | 61 + lu.traits.TakesParams.2.html | 70 + lu.traits.TakesParams.html | 1 + lu.traits.UnqualArray.1.html | 51 + lu.traits.UnqualArray.2.html | 51 + lu.traits.UnqualArray.3.html | 51 + lu.traits.UnqualArray.html | 1 + lu.traits.getSymbolsByUDA.html | 38 + lu.traits.getSymbolsByUDAImpl.html | 35 + lu.traits.html | 47 + lu.traits.isMerelyArray.html | 41 + lu.traits.isMutableArrayOfImmutables.html | 42 + lu.traits.isSerialisable.html | 52 + lu.traits.isStruct.html | 35 + lu.traits.isTrulyString.html | 41 + lu.traits.stringofParams.html | 52 + lu.typecons.UnderscoreOpDispatcher.html | 89 + ...s.UnderscoreOpDispatcher.opDispatch.1.html | 35 + ...s.UnderscoreOpDispatcher.opDispatch.2.html | 35 + ...ons.UnderscoreOpDispatcher.opDispatch.html | 1 + lu.typecons.html | 36 + lu.uda.CannotContainComments.html | 36 + lu.uda.Hidden.html | 36 + lu.uda.Quoted.html | 35 + lu.uda.Separator.html | 36 + lu.uda.Separator.token.html | 35 + lu.uda.Unserialisable.html | 35 + lu.uda.html | 38 + script.js | 180 ++ search-docs.html | 26 + search-docs.js | 421 +++++ search-results.html | 228 +++ style.css | 1593 +++++++++++++++++ 260 files changed, 15269 insertions(+) create mode 100644 .circleci/config.yml create mode 100755 .circleci/run.sh create mode 100644 index.html create mode 100644 lu.array.html create mode 100644 lu.array.uniqueKey.html create mode 100644 lu.common.FileExistsException.filename.html create mode 100644 lu.common.FileExistsException.html create mode 100644 lu.common.FileExistsException.this.1.html create mode 100644 lu.common.FileExistsException.this.2.html create mode 100644 lu.common.FileExistsException.this.html create mode 100644 lu.common.FileTypeMismatchException.attrs.html create mode 100644 lu.common.FileTypeMismatchException.filename.html create mode 100644 lu.common.FileTypeMismatchException.html create mode 100644 lu.common.FileTypeMismatchException.this.1.html create mode 100644 lu.common.FileTypeMismatchException.this.2.html create mode 100644 lu.common.FileTypeMismatchException.this.html create mode 100644 lu.common.Next.html create mode 100644 lu.common.ReturnValueException.command.html create mode 100644 lu.common.ReturnValueException.html create mode 100644 lu.common.ReturnValueException.retval.html create mode 100644 lu.common.ReturnValueException.this.1.html create mode 100644 lu.common.ReturnValueException.this.2.html create mode 100644 lu.common.ReturnValueException.this.3.html create mode 100644 lu.common.ReturnValueException.this.html create mode 100644 lu.common.html create mode 100644 lu.common.sharedDomains.html create mode 100644 lu.container.Buffer.buf.1.html create mode 100644 lu.container.Buffer.buf.2.html create mode 100644 lu.container.Buffer.buf.html create mode 100644 lu.container.Buffer.bufferSize.1.html create mode 100644 lu.container.Buffer.bufferSize.2.html create mode 100644 lu.container.Buffer.bufferSize.html create mode 100644 lu.container.Buffer.clear.html create mode 100644 lu.container.Buffer.empty.html create mode 100644 lu.container.Buffer.end.html create mode 100644 lu.container.Buffer.front.html create mode 100644 lu.container.Buffer.growthFactor.html create mode 100644 lu.container.Buffer.html create mode 100644 lu.container.Buffer.length.html create mode 100644 lu.container.Buffer.opOpAssign.html create mode 100644 lu.container.Buffer.popFront.html create mode 100644 lu.container.Buffer.pos.html create mode 100644 lu.container.Buffer.put.1.html create mode 100644 lu.container.Buffer.put.2.html create mode 100644 lu.container.Buffer.put.html create mode 100644 lu.container.Buffer.reserve.html create mode 100644 lu.container.Buffer.reset.html create mode 100644 lu.container.CircularBuffer.buf.1.html create mode 100644 lu.container.CircularBuffer.buf.2.html create mode 100644 lu.container.CircularBuffer.buf.html create mode 100644 lu.container.CircularBuffer.caughtUp.html create mode 100644 lu.container.CircularBuffer.clear.html create mode 100644 lu.container.CircularBuffer.dup.html create mode 100644 lu.container.CircularBuffer.empty.html create mode 100644 lu.container.CircularBuffer.front.html create mode 100644 lu.container.CircularBuffer.head.html create mode 100644 lu.container.CircularBuffer.html create mode 100644 lu.container.CircularBuffer.initialised.html create mode 100644 lu.container.CircularBuffer.opOpAssign.html create mode 100644 lu.container.CircularBuffer.popFront.html create mode 100644 lu.container.CircularBuffer.put.html create mode 100644 lu.container.CircularBuffer.reset.html create mode 100644 lu.container.CircularBuffer.resize.html create mode 100644 lu.container.CircularBuffer.save.html create mode 100644 lu.container.CircularBuffer.size.html create mode 100644 lu.container.CircularBuffer.tail.html create mode 100644 lu.container.MutexedAA.aa.html create mode 100644 lu.container.MutexedAA.clear.html create mode 100644 lu.container.MutexedAA.get.html create mode 100644 lu.container.MutexedAA.has.html create mode 100644 lu.container.MutexedAA.html create mode 100644 lu.container.MutexedAA.isReady.html create mode 100644 lu.container.MutexedAA.keys.html create mode 100644 lu.container.MutexedAA.length.html create mode 100644 lu.container.MutexedAA.mutex.html create mode 100644 lu.container.MutexedAA.opEquals.1.html create mode 100644 lu.container.MutexedAA.opEquals.2.html create mode 100644 lu.container.MutexedAA.opEquals.html create mode 100644 lu.container.MutexedAA.opIndex.html create mode 100644 lu.container.MutexedAA.opIndexAssign.html create mode 100644 lu.container.MutexedAA.opIndexOpAssign.html create mode 100644 lu.container.MutexedAA.opIndexUnary.html create mode 100644 lu.container.MutexedAA.rehash.html create mode 100644 lu.container.MutexedAA.remove.html create mode 100644 lu.container.MutexedAA.require.html create mode 100644 lu.container.MutexedAA.setup.html create mode 100644 lu.container.MutexedAA.uniqueKey.html create mode 100644 lu.container.MutexedAA.update.html create mode 100644 lu.container.MutexedAA.values.html create mode 100644 lu.container.RehashingAA._lengthAtLastRehash.html create mode 100644 lu.container.RehashingAA._newKeysSinceLastRehash.html create mode 100644 lu.container.RehashingAA._numRehashes.html create mode 100644 lu.container.RehashingAA.aa.html create mode 100644 lu.container.RehashingAA.aaOf.html create mode 100644 lu.container.RehashingAA.clear.html create mode 100644 lu.container.RehashingAA.dup.html create mode 100644 lu.container.RehashingAA.html create mode 100644 lu.container.RehashingAA.length.html create mode 100644 lu.container.RehashingAA.maybeRehash.html create mode 100644 lu.container.RehashingAA.minimumNeededForRehash.html create mode 100644 lu.container.RehashingAA.newKeysSinceLastRehash.html create mode 100644 lu.container.RehashingAA.numRehashes.html create mode 100644 lu.container.RehashingAA.onRehashDg.html create mode 100644 lu.container.RehashingAA.opAssign.html create mode 100644 lu.container.RehashingAA.opBinaryRight.html create mode 100644 lu.container.RehashingAA.opCast.html create mode 100644 lu.container.RehashingAA.opIndexAssign.html create mode 100644 lu.container.RehashingAA.rehash.html create mode 100644 lu.container.RehashingAA.rehashThresholdMultiplier.html create mode 100644 lu.container.RehashingAA.remove.html create mode 100644 lu.container.RehashingAA.this.html create mode 100644 lu.container.html create mode 100644 lu.conv.Enum.fromString.html create mode 100644 lu.conv.Enum.html create mode 100644 lu.conv.Enum.toString.html create mode 100644 lu.conv.enumToString.html create mode 100644 lu.conv.html create mode 100644 lu.conv.numFromHex.html create mode 100644 lu.conv.rgbFromHex.html create mode 100644 lu.conv.toAlpha.html create mode 100644 lu.conv.toAlphaInto.html create mode 100644 lu.deltastrings.formatDeltaInto.html create mode 100644 lu.deltastrings.html create mode 100644 lu.html create mode 100644 lu.json.JSONStorage.KeyOrderStrategy.html create mode 100644 lu.json.JSONStorage.html create mode 100644 lu.json.JSONStorage.load.html create mode 100644 lu.json.JSONStorage.reset.html create mode 100644 lu.json.JSONStorage.save.html create mode 100644 lu.json.JSONStorage.serialiseInto.1.html create mode 100644 lu.json.JSONStorage.serialiseInto.2.html create mode 100644 lu.json.JSONStorage.serialiseInto.html create mode 100644 lu.json.JSONStorage.storage.html create mode 100644 lu.json.html create mode 100644 lu.json.populateFromJSON.html create mode 100644 lu.meld.MeldingStrategy.html create mode 100644 lu.meld.Unmeldable.html create mode 100644 lu.meld.html create mode 100644 lu.meld.meldInto.1.html create mode 100644 lu.meld.meldInto.2.html create mode 100644 lu.meld.meldInto.3.html create mode 100644 lu.meld.meldInto.html create mode 100644 lu.numeric.getMultipleOf.html create mode 100644 lu.numeric.html create mode 100644 lu.objmanip.SetMemberException.html create mode 100644 lu.objmanip.SetMemberException.memberToSet.html create mode 100644 lu.objmanip.SetMemberException.this.1.html create mode 100644 lu.objmanip.SetMemberException.this.2.html create mode 100644 lu.objmanip.SetMemberException.this.html create mode 100644 lu.objmanip.SetMemberException.typeName.html create mode 100644 lu.objmanip.SetMemberException.valueToSet.html create mode 100644 lu.objmanip.html create mode 100644 lu.objmanip.pruneAA.html create mode 100644 lu.objmanip.replaceMembers.html create mode 100644 lu.objmanip.setMemberByName.1.html create mode 100644 lu.objmanip.setMemberByName.2.html create mode 100644 lu.objmanip.setMemberByName.html create mode 100644 lu.semver.LuSemVer.html create mode 100644 lu.semver.LuSemVerPrerelease.html create mode 100644 lu.semver.html create mode 100644 lu.serialisation.DeserialisationException.html create mode 100644 lu.serialisation.DeserialisationException.this.html create mode 100644 lu.serialisation.SerialisationUDAs.arrayPattern.html create mode 100644 lu.serialisation.SerialisationUDAs.escapedSeparator.html create mode 100644 lu.serialisation.SerialisationUDAs.html create mode 100644 lu.serialisation.SerialisationUDAs.separator.html create mode 100644 lu.serialisation.SerialisationUDAs.unserialisable.html create mode 100644 lu.serialisation.deserialise.html create mode 100644 lu.serialisation.html create mode 100644 lu.serialisation.justifiedEntryValueText.html create mode 100644 lu.serialisation.serialise.1.html create mode 100644 lu.serialisation.serialise.2.html create mode 100644 lu.serialisation.serialise.html create mode 100644 lu.serialisation.serialiseArrayImpl.html create mode 100644 lu.serialisation.splitEntryValue.html create mode 100644 lu.string.AdvanceException.haystack.html create mode 100644 lu.string.AdvanceException.html create mode 100644 lu.string.AdvanceException.needle.html create mode 100644 lu.string.AdvanceException.this.html create mode 100644 lu.string.AdvanceExceptionImpl._haystack.html create mode 100644 lu.string.AdvanceExceptionImpl._needle.html create mode 100644 lu.string.AdvanceExceptionImpl.haystack.html create mode 100644 lu.string.AdvanceExceptionImpl.html create mode 100644 lu.string.AdvanceExceptionImpl.needle.html create mode 100644 lu.string.AdvanceExceptionImpl.this.1.html create mode 100644 lu.string.AdvanceExceptionImpl.this.2.html create mode 100644 lu.string.AdvanceExceptionImpl.this.html create mode 100644 lu.string.NomException.html create mode 100644 lu.string.NomExceptionImpl.html create mode 100644 lu.string.SplitResults.html create mode 100644 lu.string.advancePast.1.html create mode 100644 lu.string.advancePast.2.html create mode 100644 lu.string.advancePast.html create mode 100644 lu.string.beginsWithOneOf.html create mode 100644 lu.string.decode64.html create mode 100644 lu.string.encode64.html create mode 100644 lu.string.escapeControlCharacters.html create mode 100644 lu.string.html create mode 100644 lu.string.indent.html create mode 100644 lu.string.indentInto.html create mode 100644 lu.string.nom.html create mode 100644 lu.string.plurality.html create mode 100644 lu.string.removeControlCharacters.html create mode 100644 lu.string.splitInto.1.html create mode 100644 lu.string.splitInto.2.html create mode 100644 lu.string.splitInto.html create mode 100644 lu.string.splitLineAtPosition.html create mode 100644 lu.string.splitWithQuotes.html create mode 100644 lu.string.stripSuffix.html create mode 100644 lu.string.stripped.1.html create mode 100644 lu.string.stripped.2.html create mode 100644 lu.string.stripped.html create mode 100644 lu.string.strippedLeft.1.html create mode 100644 lu.string.strippedLeft.2.html create mode 100644 lu.string.strippedLeft.html create mode 100644 lu.string.strippedRight.1.html create mode 100644 lu.string.strippedRight.2.html create mode 100644 lu.string.strippedRight.html create mode 100644 lu.string.tabs.html create mode 100644 lu.string.unenclosed.html create mode 100644 lu.string.unquoted.html create mode 100644 lu.string.unsinglequoted.html create mode 100644 lu.traits.CategoryName.fqn.html create mode 100644 lu.traits.CategoryName.html create mode 100644 lu.traits.CategoryName.name.html create mode 100644 lu.traits.MixinConstraints.html create mode 100644 lu.traits.MixinScope.html create mode 100644 lu.traits.TakesParams.1.html create mode 100644 lu.traits.TakesParams.2.html create mode 100644 lu.traits.TakesParams.html create mode 100644 lu.traits.UnqualArray.1.html create mode 100644 lu.traits.UnqualArray.2.html create mode 100644 lu.traits.UnqualArray.3.html create mode 100644 lu.traits.UnqualArray.html create mode 100644 lu.traits.getSymbolsByUDA.html create mode 100644 lu.traits.getSymbolsByUDAImpl.html create mode 100644 lu.traits.html create mode 100644 lu.traits.isMerelyArray.html create mode 100644 lu.traits.isMutableArrayOfImmutables.html create mode 100644 lu.traits.isSerialisable.html create mode 100644 lu.traits.isStruct.html create mode 100644 lu.traits.isTrulyString.html create mode 100644 lu.traits.stringofParams.html create mode 100644 lu.typecons.UnderscoreOpDispatcher.html create mode 100644 lu.typecons.UnderscoreOpDispatcher.opDispatch.1.html create mode 100644 lu.typecons.UnderscoreOpDispatcher.opDispatch.2.html create mode 100644 lu.typecons.UnderscoreOpDispatcher.opDispatch.html create mode 100644 lu.typecons.html create mode 100644 lu.uda.CannotContainComments.html create mode 100644 lu.uda.Hidden.html create mode 100644 lu.uda.Quoted.html create mode 100644 lu.uda.Separator.html create mode 100644 lu.uda.Separator.token.html create mode 100644 lu.uda.Unserialisable.html create mode 100644 lu.uda.html create mode 100644 script.js create mode 100644 search-docs.html create mode 100644 search-docs.js create mode 100644 search-results.html create mode 100644 style.css diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..4e857566 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,33 @@ +version: 2 + +jobs: + build: + docker: + - image: cimg/base:2021.11 + steps: + - checkout + - run: + name: Install compilers + command: ./.circleci/run.sh install-deps + - run: + name: Build and test (dmd) + command: ./.circleci/run.sh build-dmd + - run: + name: Build and test (ldc) + command: ./.circleci/run.sh build-ldc + #- store_artifacts: + #path: ./artifacts + +workflows: + version: 2 + build_and_test: + jobs: + - build: + filters: + branches: + ignore: + - /appveyor-.*/ + - /travis-.*/ + - gh-pages + - /dustmite-.*/ + - /github-.*/ diff --git a/.circleci/run.sh b/.circleci/run.sh new file mode 100755 index 00000000..94abc0c5 --- /dev/null +++ b/.circleci/run.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +set -uexo pipefail + +#DMD_VERSION="2.098.0" +#LDC_VERSION="1.28.0" +CURL_USER_AGENT="CirleCI $(curl --version | head -n 1)" + +update_repos() { + sudo apt-get update +} + +install_deps() { + sudo apt-get install g++-multilib + + # required for: "core.time.TimeException@std/datetime/timezone.d(2073): Directory /usr/share/zoneinfo/ does not exist." + #sudo apt-get install --reinstall tzdata gdb +} + +download_install_script() { + for i in {0..4}; do + if curl -fsS -A "$CURL_USER_AGENT" --max-time 5 https://dlang.org/install.sh -O || + curl -fsS -A "$CURL_USER_AGENT" --max-time 5 https://nightlies.dlang.org/install.sh -O ; then + break + elif [[ "$i" -ge 4 ]]; then + sleep $((1 << i)) + else + echo 'Failed to download install script' 1>&2 + exit 1 + fi + done +} + +install_and_activate_compiler() { + local compiler compiler_version_ext compiler_build + + compiler=$1 + [[ $# -gt 1 ]] && compiler_version_ext="-$2" || compiler_version_ext="" + compiler_build="${compiler}${compiler_version_ext}" + + source "$(CURL_USER_AGENT=\"$CURL_USER_AGENT\" bash install.sh $compiler_build --activate)" +} + +use_lu_master() { + if [[ ! -d lu ]]; then + git clone https://github.com/zorael/lu.git + dub add-local lu + fi +} + +build() { + local compiler_switch arch_switch + + compiler_switch="--compiler=$1" + arch_switch="--arch=$2" + + shift 2 # shift away compiler and arch + # "$@" is now any extra parameters passed to build + + dub clean + + time dub test $compiler_switch $arch_switch "$@" + time dub build $compiler_switch $arch_switch "$@" --nodeps -b debug + time dub build $compiler_switch $arch_switch "$@" --nodeps -b plain + time dub build $compiler_switch $arch_switch "$@" --nodeps -b release +} + +# execution start + +case $1 in + install-deps) + update_repos + install_deps + download_install_script + ;; + + build-dmd) + install_and_activate_compiler dmd #"$DMD_VERSION" + dmd --version + dub --version + + #use_lu_master + + #time build dmd x86 # no 32-bit libs? + time build dmd x86_64 + ;; + + build-ldc) + install_and_activate_compiler ldc #"$LDC_VERSION" + ldc2 --version + dub --version + + #use_lu_master + + #time build ldc2 x86 # no 32-bit libs? + time build ldc2 x86_64 + ;; + + *) + echo "Unknown command: $1"; + exit 1; + ;; +esac + +exit 0 diff --git a/index.html b/index.html new file mode 100644 index 00000000..2aa4426c --- /dev/null +++ b/index.html @@ -0,0 +1,35 @@ + + +
+Returns a unique key for the passed associative array. Reserves the key by + assigning it a value.
Note: This function will end up in an endless loop if a narrow range of indexes + is supplied and the associative array already contains values for all of them.
Associative array to get a unique key for.
Optional minimum key value; defaults to 1.
Optional maximum key value; defaults to K.max, where K is the + key type of the passed associative array.
Optional value to assign to the key; defaults to V.init, where + V is the value type of the passed associative array.
A unique key for the passed associative array. There will exist an array + entry for the key, with the value value.
string[int] aa; +immutable key = aa.uniqueKey; +assert(key > 0); +assert(key in aa); +assert(aa[key] == string.init);
import std.conv : to; + +{ + string[int] aa; + immutable key = aa.uniqueKey; + assert(key in aa); +} +{ + long[long] aa; + immutable key = aa.uniqueKey; + assert(key in aa); +} +{ + shared bool[int] aa; + immutable key = aa.uniqueKey; + assert(key in aa); +} +{ + int[int] aa; + immutable key = aa.uniqueKey(5, 6, 42); + assert(key == 5); + assert((aa[5] == 42), aa[5].to!string); +}
The name of the file.
Exception, to be thrown when attempting to create a file or directory and + finding that one already exists with the same name.
It is a normal Exception but with an attached filename string.
Create a new FileExistsException, without attaching a filename.
Create a new FileExistsException, attaching a filename.
The name of the file.
Create a new FileExistsException, without attaching a filename.
Create a new FileExistsException, attaching a filename.
File attributes.
The filename of the non-FIFO.
Exception, to be thrown when attempting to access a file or directory and + finding that something with the that name exists, but is of an unexpected type.
It is a normal Exception but with an embedded filename + string, and an uint representing the existing file's type (file, directory, + symlink, ...).
Create a new FileTypeMismatchException, without embedding a filename.
Create a new FileTypeMismatchException, embedding a filename.
Create a new FileTypeMismatchException, without embedding a filename.
Create a new FileTypeMismatchException, embedding a filename.
Enum of flags carrying the meaning of "what to do next".
Value | Meaning |
---|---|
unset | Unset, invalid value. |
noop | Do nothing. |
continue_ | Keep doing whatever is being done, alternatively continue on to the next step. |
retry | Halt what's being done and give it another attempt. |
returnSuccess | Exit or return with a positive return value. |
returnFailure | Exit or abort with a negative return value. |
crash | Fatally abort. |
The command run.
Exception, to be thrown when an executed command returns an error value.
It is a normal Exception but with an attached command + and return value.
Create a new ReturnValueException, without attaching anything.
Create a new ReturnValueException, attaching a command.
Create a new ReturnValueException, attaching a command and a returned value.
The value returned.
Create a new ReturnValueException, without attaching anything.
Create a new ReturnValueException, attaching a command.
Create a new ReturnValueException, attaching a command and a returned value.
Functionality generic enough to be used in several places.
Exception, to be thrown when attempting to create a file or directory and + finding that one already exists with the same name.
Exception, to be thrown when attempting to access a file or directory and + finding that something with the that name exists, but is of an unexpected type.
Exception, to be thrown when an executed command returns an error value.
Enum of flags carrying the meaning of "what to do next".
Calculates how many dot-separated suffixes two strings share.
Calculates how many dot-separated suffixes two strings share.
This is useful to see to what extent two addresses are similar.
First domain string.
Second domain string.
Whether or not comparison should be done on a + case-sensitive basis.
The number of domains the two strings share.
TODO: + Support partial globs.
int numDomains = sharedDomains("irc.freenode.net", "leguin.freenode.net"); +assert(numDomains == 2); // freenode.net + +int numDomains2 = sharedDomains("Portlane2.EU.GameSurge.net", "services.gamesurge.net", No.caseSensitive); +assert(numDomains2 == 2); // gamesurge.net
import std.conv : text; + +immutable n1 = sharedDomains("irc.freenode.net", "help.freenode.net"); +assert((n1 == 2), n1.text); + +immutable n2 = sharedDomains("irc.rizon.net", "services.rizon.net"); +assert((n2 == 2), n2.text); + +immutable n3 = sharedDomains("www.google.com", "www.yahoo.com"); +assert((n3 == 1), n3.text); + +immutable n4 = sharedDomains("www.google.se", "www.google.co.uk"); +assert((n4 == 0), n4.text); + +immutable n5 = sharedDomains("", string.init); +assert((n5 == 0), n5.text); + +immutable n6 = sharedDomains("irc.rizon.net", "rizon.net"); +assert((n6 == 2), n6.text); + +immutable n7 = sharedDomains("rizon.net", "rizon.net"); +assert((n7 == 2), n7.text); + +immutable n8 = sharedDomains("net", "net"); +assert((n8 == 1), n8.text); + +immutable n9 = sharedDomains("forum.dlang.org", "..."); +assert((n9 == 0), n8.text); + +immutable n10 = sharedDomains("blahrizon.net", "rizon.net"); +assert((n10 == 1), n10.text); + +immutable n11 = sharedDomains("rizon.net", "blahrizon.net"); +assert((n11 == 1), n11.text); + +immutable n12 = sharedDomains("rizon.net", "irc.rizon.net"); +assert((n12 == 2), n12.text); + +immutable n13 = sharedDomains("irc.gamesurge.net", "Stuff.GameSurge.net", No.caseSensitive); +assert((n13 == 2), n13.text); + +immutable n14 = sharedDomains("irc.freenode.net", "irc.FREENODE.net", No.caseSensitive); +assert((n14 == 3), n14.text); + +immutable n15 = sharedDomains("irc.SpotChat.org", "irc.FREENODE.net", No.caseSensitive); +assert((n15 == 0), n15.text);
Internal buffer dynamic array.
Internal buffer static array.
Variable buffer size.
Static buffer size.
Zeroes out the buffer's elements, getting rid of old contents.
Returns whether or not the container is considered empty.
Mind that the buffer may well still contain old contents. Use clear + to zero it out.
true if there are items available to get via front, + false if not.
Position of last entry in the array.
Fetches the item at the current position of the buffer.
An item T.
By how much to grow the buffer when we reach the end of it.
Simple buffer/queue for storing and fetching items of any type T. + Does not use manual memory allocation.
It can use a static array internally to store elements on the stack, which + imposes a hard limit on how many items can be added, or a dynamic heap one + with a resizable buffer.
Static buffer size.
Zeroes out the buffer's elements, getting rid of old contents.
Returns whether or not the container is considered empty.
Fetches the item at the current position of the buffer.
Returns what amounts to the current length of the buffer; the distance + between the current position pos and the last element end.
Implements buf ~= someT (appending) by wrapping put.
Advances the current position to the next item in the buffer.
Append an item to the end of the buffer.
Append an item to the end of the buffer.
Reserves enough room for the specified number of elements. If there + is already enough room, nothing is done. Otherwise the buffer is grown.
Resets the array positions, effectively soft-emptying the buffer.
By how much to grow the buffer when we reach the end of it.
Internal buffer dynamic array.
Internal buffer static array.
Variable buffer size.
Position of last entry in the array.
Current position in the array.
Buffer item type.
Whether to use a dynamic array whose size can be grown at + runtime, or to use a static array with a fixed size. Trying to add + more elements than there is room for will cause an assert. + Defaults to No.dynamic; a static array.
How many items to allocate space for. If No.dynamic was + passed it will assert if you attempt to store anything past this amount.
Buffer!(string, No.dynamic, 16) buffer; + +buffer.put("abc"); +buffer ~= "def"; +assert(!buffer.empty); +assert(buffer.front == "abc"); +buffer.popFront(); +assert(buffer.front == "def"); +buffer.popFront(); +assert(buffer.empty);
1 { +2 Buffer!(bool, No.dynamic, 4) buffer; +3 +4 assert(buffer.empty); +5 buffer.put(true); +6 buffer.put(false); +7 assert(buffer.length == 2); +8 buffer.put(true); +9 buffer.put(false); +10 +11 assert(!buffer.empty); +12 assert(buffer.front == true); +13 buffer.popFront(); +14 assert(buffer.front == false); +15 buffer.popFront(); +16 assert(buffer.front == true); +17 buffer.popFront(); +18 assert(buffer.front == false); +19 buffer.popFront(); +20 assert(buffer.empty); +21 assert(buffer.buf == [ true, false, true, false ]); +22 buffer.put(false); +23 assert(buffer.buf == [ false, false, true, false ]); +24 buffer.reset(); +25 assert(buffer.empty); +26 buffer.clear(); +27 assert(buffer.buf == [ false, false, false, false ]); +28 } +29 { +30 Buffer!(string, No.dynamic, 4) buffer; +31 +32 assert(buffer.empty); +33 buffer.put("abc"); +34 buffer.put("def"); +35 buffer.put("ghi"); +36 +37 assert(!buffer.empty); +38 assert(buffer.front == "abc"); +39 buffer.popFront(); +40 assert(buffer.front == "def"); +41 buffer.popFront(); +42 buffer.put("JKL"); +43 assert(buffer.front == "ghi"); +44 buffer.popFront(); +45 assert(buffer.front == "JKL"); +46 buffer.popFront(); +47 assert(buffer.empty); +48 assert(buffer.buf == [ "abc", "def", "ghi", "JKL" ]); +49 buffer.put("MNO"); +50 assert(buffer.buf == [ "MNO", "def", "ghi", "JKL" ]); +51 buffer.clear(); +52 assert(buffer.buf == [ string.init, string.init, string.init, string.init ]); +53 } +54 { +55 Buffer!(char, No.dynamic, 64) buffer; +56 buffer ~= 'a'; +57 buffer ~= 'b'; +58 buffer ~= 'c'; +59 assert(buffer.buf[0..3] == "abc"); +60 +61 foreach (char_; buffer) +62 { +63 assert((char_ == 'a') || (char_ == 'b') || (char_ == 'c')); +64 } +65 } +66 { +67 Buffer!(int, Yes.dynamic, 3) buffer; +68 assert(!buffer.buf.length); +69 buffer ~= 1; +70 assert(buffer.buf.length == 3); +71 buffer ~= 2; +72 buffer ~= 3; +73 assert(buffer.front == 1); +74 buffer.popFront(); +75 assert(buffer.front == 2); +76 buffer.popFront(); +77 assert(buffer.front == 3); +78 buffer.popFront(); +79 assert(buffer.empty); +80 buffer.reserve(64); +81 assert(buffer.buf.length == 64); +82 buffer.reserve(63); +83 assert(buffer.buf.length == 64); +84 } +85 { +86 Buffer!(char, No.dynamic, 4) buffer; +87 buffer ~= 'a'; +88 buffer ~= 'b'; +89 buffer ~= 'c'; +90 buffer ~= 'd'; +91 assert(buffer.buf == "abcd"); +92 assert(buffer.length == 4); +93 buffer.reset(); +94 assert(buffer.buf == "abcd"); +95 buffer.clear(); +96 assert(buffer.buf == typeof(buffer.buf).init); +97 }
Returns what amounts to the current length of the buffer; the distance + between the current position pos and the last element end.
The buffer's current length.
Implements buf ~= someT (appending) by wrapping put.
Advances the current position to the next item in the buffer.
Current position in the array.
Append an item to the end of the buffer.
If it would be put beyond the end of the buffer, it will be resized to fit.
Item to add.
Append an item to the end of the buffer.
If it would be put beyond the end of the buffer, it will assert.
Item to add.
Reserves enough room for the specified number of elements. If there + is already enough room, nothing is done. Otherwise the buffer is grown.
Number of elements to reserve size for.
Resets the array positions, effectively soft-emptying the buffer.
The old elements' values are still there, they will just be overwritten + as the buffer is appended to.
Internal buffer dynamic array.
Internal buffer static array.
Zeroes out the buffer's elements, getting rid of old contents.
Makes a deep(er) duplicate of the container.
A copy of the current container with the internal buffer explicitly .duped.
Returns whether or not the container is considered empty.
Mind that the buffer may well still contain old contents. Use clear + to zero it out.
true if there are items available to get via front, + false if not.
Head position in the internal buffer.
Simple circular-ish buffer for storing items of type T that discards elements + when the maximum size is reached. Does not use manual memory allocation.
It can use a static array internally to store elements on the stack, which + imposes a hard limit on how many items can be added, or a dynamic heap one + with a resizable buffer.
Zeroes out the buffer's elements, getting rid of old contents.
Makes a deep(er) duplicate of the container.
Returns whether or not the container is considered empty.
Returns the front element.
Implements buf ~= someT (appending) by wrapping put.
Advances the current position to the next item in the buffer.
Append an item to the buffer.
Resets the buffer pointers but doesn't clear the contents.
Resizes the internal buffer to a specified size.
Implements Range save.
Returns the size of the internal buffer.
Internal buffer dynamic array.
Internal buffer static array.
Head position in the internal buffer.
Whether or not at least one element has been added.
Tail position in the internal buffer.
Buffer item type.
Whether to use a dynamic array whose size can be grown at + runtime, or to use a static array with a fixed size. Trying to add + more elements than there is room for will wrap around and discard elements. + Defaults to No.dynamic; a static buffer.
How many items to allocate space for in the case of a + static array.
CircularBuffer!(int, Yes.dynamic) buf; +buf.resize(3); +buf.put(1); +buf.put(2); +buf.put(3); +but.put(4); +assert(buf.front == 4); +assert(buf.buf == [ 4, 2, 3 ]);
1 import std.conv : text; +2 +3 { +4 CircularBuffer!(int, Yes.dynamic) buf; +5 buf.resize(3); +6 +7 buf.put(1); +8 assert((buf.front == 1), buf.front.text); +9 buf.put(2); +10 assert((buf.front == 2), buf.front.text); +11 buf.put(3); +12 assert((buf.front == 3), buf.front.text); +13 buf ~= 4; +14 assert((buf.front == 4), buf.front.text); +15 assert((buf.buf[] == [ 4, 2, 3 ]), buf.buf.text); +16 buf ~= 5; +17 assert((buf.front == 5), buf.front.text); +18 buf ~= 6; +19 assert((buf.front == 6), buf.front.text); +20 assert((buf.buf[] == [ 4, 5, 6 ]), buf.buf.text); +21 buf.popFront(); +22 buf.popFront(); +23 buf.popFront(); +24 assert(buf.empty); +25 } +26 { +27 CircularBuffer!(int, No.dynamic, 3) buf; +28 //buf.resize(3); +29 +30 buf.put(1); +31 assert((buf.front == 1), buf.front.text); +32 buf.put(2); +33 assert((buf.front == 2), buf.front.text); +34 buf.put(3); +35 assert((buf.front == 3), buf.front.text); +36 buf ~= 4; +37 assert((buf.front == 4), buf.front.text); +38 assert((buf.buf[] == [ 4, 2, 3 ]), buf.buf.text); +39 buf.popFront(); +40 buf.popFront(); +41 buf.popFront(); +42 assert(buf.empty); +43 } +44 { +45 CircularBuffer!(int, No.dynamic, 2) buf; +46 //buf.resize(2); +47 +48 buf.put(1); +49 assert((buf.front == 1), buf.front.text); +50 buf.put(2); +51 assert((buf.front == 2), buf.front.text); +52 buf.put(3); +53 assert((buf.front == 3), buf.front.text); +54 buf ~= 4; +55 assert((buf.front == 4), buf.front.text); +56 assert((buf.buf[] == [ 3, 4 ]), buf.buf.text); +57 buf.popFront(); +58 buf.popFront(); +59 assert(buf.empty); +60 //buf.popFront(); // AssertError +61 } +62 { +63 CircularBuffer!(int, No.dynamic, 2) buf; +64 //buf.resize(2); +65 +66 buf.put(1); +67 assert((buf.front == 1), buf.front.text); +68 buf.put(2); +69 assert((buf.front == 2), buf.front.text); +70 buf.put(3); +71 assert((buf.front == 3), buf.front.text); +72 buf ~= 4; +73 assert((buf.front == 4), buf.front.text); +74 assert((buf.buf[] == [ 3, 4 ]), buf.buf.text); +75 auto savedBuf = buf.save(); +76 buf.popFront(); +77 buf.popFront(); +78 assert(buf.empty); +79 assert((savedBuf.front == 4), savedBuf.front.text); +80 savedBuf.popFront(); +81 auto savedBuf2 = savedBuf.save(); +82 savedBuf.popFront(); +83 assert(savedBuf.empty); +84 assert((savedBuf2.front == 3), savedBuf2.front.text); +85 savedBuf2.popFront(); +86 assert(savedBuf2.empty); +87 }
Whether or not at least one element has been added.
Advances the current position to the next item in the buffer.
Append an item to the buffer.
If it would be put beyond the end of the buffer, it will wrap around and + truncate old values.
Item to add.
Resets the buffer pointers but doesn't clear the contents.
Resizes the internal buffer to a specified size.
New size.
Returns the size of the internal buffer.
Internal buffer size.
Tail position in the internal buffer.
The internal associative array.
Clears the internal associative array.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +aa[1] = "one"; +aa[2] = "two"; +assert(aa.has(1)); + +aa.clear(); +assert(!aa.has(2));
Retrieves the value for the key key, or returns the default value + if there was none.
The value for the key key, or value if there was no value there.
MutexedAA!(int[int]) aa; +aa.setup(); // important! +aa[1] = 42; +aa[2] = 99; + +assert(aa.get(1, 0) == 42); +assert(aa.get(2, 0) == 99); +assert(aa.get(0, 0) == 0); +assert(aa.get(3, 999) == 999); + +assert(!aa.has(0)); +assert(!aa.has(3));
Returns whether or not the passed key is in the associative array.
Key.
true if the key is in the associative array; false if not.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +aa[1] = "one"; +assert(aa.has(1));
An associative array and a Mutex. Wraps associative + array operations in mutex locks.
Clears the internal associative array.
Retrieves the value for the key key, or returns the default value + if there was none.
Returns whether or not the passed key is in the associative array.
Returns whether or not this instance has been set up.
Returns a new dynamic array of all the keys in the internal associative array.
Returns the length of the internal associative array.
Implements opEquals for this type, comparing the internal associative + array with that of another MutexedAA.
Implements opEquals for this type, comparing the internal associative + array with a different one.
aa[key] array retrieve operation, wrapped in a mutex lock.
aa[key] = value array assign operation, wrapped in a mutex lock.
Implements index assign operations by mixin strings.
Implements unary operations by mixin strings.
Rehashes the internal associative array.
aa.remove(key) array operation, wrapped in a mutex lock.
Returns the value for the key key, inserting value lazily if it is not present.
Sets up this instance. Does nothing if it has already been set up.
Reserves a unique key in the associative array.
Updates the value for the key key in the internal associative array, + invoking the first of the passed delegate to insert a new value if it + doesn't exist, or the second selegate to modify it in place if it does.
Returns a new dynamic array of all the values in the internal associative array.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +aa[1] = "one"; +aa[2] = "two"; +aa[3] = "three"; + +auto hasOne = aa.has(1); +assert(hasOne); +assert(aa[1] == "one"); + +assert(aa[2] == "two"); + +auto three = aa.get(3); +assert(three == "three"); + +auto four = aa.get(4, "four"); +assert(four == "four"); + +auto five = aa.require(5, "five"); +assert(five == "five"); +assert(aa[5] == "five"); + +auto keys = aa.keys; +assert(keys.canFind(1)); +assert(keys.canFind(5)); +assert(!keys.canFind(6)); + +auto values = aa.values; +assert(values.canFind("one")); +assert(values.canFind("four")); +assert(!values.canFind("six")); + +aa.rehash();
1 { +2 MutexedAA!(string[int]) aa1; +3 assert(!aa1.isReady); +4 aa1.setup(); +5 assert(aa1.isReady); +6 aa1.setup(); // extra setups ignored +7 +8 MutexedAA!(string[int]) aa2; +9 aa2.setup(); +10 +11 aa1[42] = "hello"; +12 aa2[42] = "world"; +13 assert(aa1 != aa2); +14 +15 aa1[42] = "world"; +16 assert(aa1 == aa2); +17 +18 aa2[99] = "goodbye"; +19 assert(aa1 != aa2); +20 } +21 { +22 MutexedAA!(string[int]) aa; +23 aa.setup(); +24 +25 assert(!aa.has(42)); +26 aa.require(42, "hello"); +27 assert((aa[42] == "hello"), aa[42]); +28 +29 bool set1; +30 assert(!aa.has(99)); +31 string world1 = aa.require(99, { set1 = true; return "world"; }()); +32 assert(set1); +33 assert((world1 == "world"), world1); +34 assert((aa[99] == "world"), aa[99]); +35 +36 bool set2; +37 string world2 = aa.require(99, { set2 = true; return "goodbye"; }()); +38 assert(!set2); +39 assert((world2 != "goodbye"), world2); +40 assert((aa[99] != "goodbye"), aa[99]); +41 } +42 { +43 import std.concurrency : Tid, send, spawn; +44 import std.conv : to; +45 import core.time : MonoTime, seconds; +46 +47 static immutable timeout = 1.seconds; +48 +49 static void workerFn(MutexedAA!(string[int]) aa) +50 { +51 static void _assert( +52 lazy bool condition, +53 const string message = "unittest failure", +54 const string file = __FILE__, +55 const uint line = __LINE__) +56 { +57 if (!condition) +58 { +59 import std.format : format; +60 import std.stdio : writeln; +61 +62 enum pattern = "core.exception.AssertError@%s(%d): %s"; +63 immutable assertMessage = pattern.format(file, line, message); +64 writeln(assertMessage); +65 assert(0, assertMessage); +66 } +67 } +68 +69 _assert(aa.isReady, "MutexedAA passed to worker was not set up properly"); +70 +71 bool halt; +72 +73 while (!halt) +74 { +75 import std.concurrency : OwnerTerminated, receiveTimeout; +76 import std.variant : Variant; +77 +78 immutable receivedSomething = receiveTimeout(timeout, +79 (bool _) +80 { +81 halt = true; +82 }, +83 (int i) +84 { +85 _assert((aa.length == i-1), "Incorrect MutexedAA length before insert"); +86 aa[i] = i.to!string; +87 _assert((aa.length == i), "Incorrect MutexedAA length after insert"); +88 }, +89 (OwnerTerminated _) +90 { +91 halt = true; +92 }, +93 (Variant v) +94 { +95 import std.stdio : writeln; +96 writeln("MutexedAA unit test worker received unknown message: ", v); +97 halt = true; +98 } +99 ); +100 +101 if (!receivedSomething) return; +102 } +103 } +104 +105 MutexedAA!(string[int]) aa; +106 aa.setup(); +107 +108 auto worker = spawn(&workerFn, aa); +109 immutable start = MonoTime.currTime; +110 +111 foreach (/*immutable*/ i; 1..10) // start at 1 to enable length checks in worker +112 { +113 worker.send(i); +114 aa.setup(); +115 auto present = aa.has(i); +116 +117 while (!present && (MonoTime.currTime - start) < timeout) +118 { +119 import core.thread : Thread; +120 import core.time : msecs; +121 +122 static immutable briefWait = 2.msecs; +123 Thread.sleep(briefWait); +124 present = aa.has(i); +125 } +126 +127 assert(present, "MutexedAA unit test worker timed out responding to " ~ i.to!string); +128 assert((aa[i] == i.to!string), aa[i]); +129 } +130 +131 worker.send(true); // halt +132 } +133 { +134 import std.algorithm.searching : canFind; +135 +136 MutexedAA!(int[int]) aa; +137 aa.setup(); +138 +139 aa[1] = 42; +140 aa[2] = 99; +141 assert(aa.length == 2); +142 +143 auto keys = aa.keys; +144 assert(keys.canFind(1)); +145 assert(keys.canFind(2)); +146 assert(!keys.canFind(3)); +147 +148 auto values = aa.values; +149 assert(values.canFind(42)); +150 assert(values.canFind(99)); +151 assert(!values.canFind(0)); +152 +153 assert(aa.get(1, 0) == 42); +154 assert(aa.get(2, 0) == 99); +155 assert(aa.get(0, 0) == 0); +156 assert(aa.get(3, 999) == 999); +157 } +158 { +159 MutexedAA!(int[int]) aa1; +160 aa1.setup(); +161 +162 aa1[1] = 42; +163 aa1[2] = 99; +164 +165 int[int] aa2; +166 +167 aa2[1] = 42; +168 assert(aa1 != aa2); +169 +170 aa2[2] = 99; +171 assert(aa1 == aa2); +172 +173 ++aa2[2]; +174 assert(aa2[2] == 100); +175 +176 aa2[1] += 1; +177 assert(aa2[1] == 43); +178 +179 aa2[1] -= 1; +180 assert(aa2[1] == 42); +181 +182 aa2[1] *= 2; +183 assert(aa2[1] == 84); +184 +185 int i = -aa2[1]; +186 assert(i == -84); +187 } +188 { +189 MutexedAA!(char[][int]) aa; +190 aa.setup(); +191 +192 aa[1] ~= 'a'; +193 aa[1] ~= 'b'; +194 aa[1] ~= 'c'; +195 assert(aa[1] == "abc".dup); +196 +197 aa[1] ~= [ 'd', 'e', 'f' ]; +198 assert(aa[1] == "abcdef".dup); +199 } +200 { +201 MutexedAA!(int[int]) aa; +202 aa.setup(); +203 +204 immutable key = aa.uniqueKey; +205 assert(key > 0); +206 +207 assert(aa.has(key)); +208 assert(aa[key] == int.init); +209 aa.remove(key); +210 assert(!aa.has(key)); +211 +212 immutable key2 = aa.uniqueKey(1, 2, -1); +213 assert(key2 == 1); +214 assert(aa.has(key2)); +215 assert(aa[key2] == -1); +216 } +217 static if (__VERSION__ >= 2088L) +218 { +219 MutexedAA!(int[int]) aa; +220 aa.setup(); +221 +222 assert(!aa.has(1)); +223 +224 aa.update(1, +225 () => 42, +226 (int i) => i + 1); +227 assert(aa.has(1)); +228 assert(aa[1] == 42); +229 +230 aa.update(1, +231 () => 42, +232 (int i) => i + 1); +233 assert(aa[1] == 43); +234 }
Returns whether or not this instance has been set up.
Returns a new dynamic array of all the keys in the internal associative array.
A new K[] of all the AA keys.
MutexedAA!(int[int]) aa; +aa.setup(); // important! +aa[1] = 42; +aa[2] = 99; + +auto keys = aa.keys; +assert(keys.canFind(1)); +assert(keys.canFind(2)); +assert(!keys.canFind(3));
Returns the length of the internal associative array.
The length of the internal associative array.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +assert(aa.length == 0); +aa[1] = "one"; +aa[2] = "two"; +assert(aa.length == 2);
Mutex to lock the associative array with.
Implements opEquals for this type, comparing the internal associative + array with that of another MutexedAA.
Other MutexedAA whose internal associative array to compare + with the one of this instance.
true if the internal associative arrays are equal; false if not.
MutexedAA!(string[int]) aa1; +aa1.setup(); // important! +aa1[1] = "one"; + +MutexedAA!(string[int]) aa2; +aa2.setup(); // as above +aa2[1] = "one"; +assert(aa1 == aa2); + +aa2[2] = "two"; +assert(aa1 != aa2); + +aa1[2] = "two"; +assert(aa1 == aa2);
Implements opEquals for this type, comparing the internal associative + array with a different one.
Other associative array to compare the internal one with.
true if the internal associative arrays are equal; false if not.
MutexedAA!(string[int]) aa1; +aa1.setup(); // important! +aa1[1] = "one"; +aa1[2] = "two"; + +string[int] aa2; +aa2[1] = "one"; + +assert(aa1 != aa2); + +aa2[2] = "two"; +assert(aa1 == aa2);
aa[key] array retrieve operation, wrapped in a mutex lock.
Key.
The value assigned.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +// ... + +string one = aa[1]; +writeln(aa[2]);
aa[key] = value array assign operation, wrapped in a mutex lock.
The value assigned.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +aa[1] = "one"; +aa[2] = "two";
Implements index assign operations by mixin strings.
MutexedAA!(int[int]) aa; +aa.setup(); // important! + +aa[1] = 42; +aa[1] += 1; +assert(aa[1] == 43); + +aa[1] *= 2; +assert(aa[1] == 86);
Implements unary operations by mixin strings.
The result of the operation.
MutexedAA!(int[int]) aa; +aa.setup(); // important! + +aa[1] = 42; +assert(-aa[1] == -42);
Rehashes the internal associative array.
A reference to the rehashed internal array.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +aa[1] = "one"; +aa[2] = "two"; +aa.rehash();
aa.remove(key) array operation, wrapped in a mutex lock.
Key.
Whatever aa.remove(key) returns.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +aa[1] = "one"; +assert(aa.has(1)); + +aa.remove(1); +assert(!aa.has(1));
Returns the value for the key key, inserting value lazily if it is not present.
The value for the key key, or value if there was no value there.
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +assert(!aa.has(42)); +string hello = aa.require(42, "hello"); +assert(hello == "hello"); +assert(aa[42] == "hello");
Sets up this instance. Does nothing if it has already been set up.
Instantiates the mutex and minimally initialises the associative array + by assigning and removing a dummy value.
Reserves a unique key in the associative array.
Note: The key type must be an integral type.
Optional minimum key value; defaults to 1`.
Optional maximum key value; defaults to K.max, where K is + the key type of the passed associative array.
Optional value to assign to the key; defaults to V.init, + where V is the value type of the passed associative array.
A unique key for the passed associative array, for which there is now + a value of value.`
MutexedAA!(string[int]) aa; +aa.setup(); // important! + +int i = aa.uniqueKey; +assert(i > 0); +assert(aa.has(i)); +assert(aa[i] == string.init);
Updates the value for the key key in the internal associative array, + invoking the first of the passed delegate to insert a new value if it + doesn't exist, or the second selegate to modify it in place if it does.
Note: Doesn't compile with compilers earlier than version 2.088.
Key.
Delegate to invoke to create a new value if it doesn't exist.
Delegate to invoke to update an existing value.
MutexedAA!(int[int]) aa; +aa.setup(); // important! + +assert(!aa.has(1)); + +aa.update(1, + () => 42, + (int i) => i + 1); +assert(aa[1] == 42); + +aa.update(1, + () => 42, + (int i) => i + 1); +assert(aa[1] == 43);
Returns a new dynamic array of all the values in the internal associative array.
A new V[] of all the AA values.
MutexedAA!(int[int]) aa; +aa.setup(); // important! +aa[1] = 42; +aa[2] = 99; + +auto values = aa.values; +assert(values.canFind(42)); +assert(values.canFind(99)); +assert(!values.canFind(0));
The number of keys (and length of the array) when the last rehash took place. + Private value.
The number of new entries that has been added since the last rehash. Private value.
The number of times this instance has rehashed itself. Private value.
Internal associative array.
Returns the internal associative array, for when the wrapper is insufficient.
The internal associative array.
Clears the internal associative array and all counters.
Duplicates this. Explicitly copies the internal associative array.
A duplicate of this object.
A wrapper around a native associative array that you can controllably set to + automatically rehash as entries are added.
Constructor.
Returns the internal associative array, for when the wrapper is insufficient.
Clears the internal associative array and all counters.
Duplicates this. Explicitly copies the internal associative array.
Returns the length of the internal associative array.
Bumps the internal counter of new keys since the last rehash, and depending + on the resulting value of it, maybe rehashes.
The number of new entries that has been added since the last rehash. Accessor.
The number of times this instance has rehashed itself. Accessor.
Inherit a native associative array into aa.
Wraps key in aa to the internal associative array.
Allows for casting this into the base associative array type.
Assigns a value into the internal associative array. If it created a new + entry, then call maybeRehash to bump the internal counter and maybe rehash.
Rehashes the internal associative array, bumping the rehash counter and + zeroing the keys-added counter. Additionally invokes the onRehashDg delegate.
Removes a key from the aa associative array by merely + invoking .remove.
The number of keys (and length of the array) when the last rehash took place. + Private value.
The number of new entries that has been added since the last rehash. Private value.
The number of times this instance has rehashed itself. Private value.
Internal associative array.
The minimum number of additions needed before the first rehash takes place.
Delegate called when rehashing takes place.
The modifier by how much more entries must be added before another rehash + takes place, with regards to the current aa length.
import std.conv : to; + +RehashingAA!(int[string]) aa; +aa.minimumNeededForRehash = 2; + +aa["abc"] = 123; +aa["def"] = 456; +assert((aa.newKeysSinceLastRehash == 2), aa.newKeysSinceLastRehash.to!string); +assert((aa.numRehashes == 0), aa.numRehashes.to!string); +aa["ghi"] = 789; +assert((aa.numRehashes == 1), aa.numRehashes.to!string); +assert((aa.newKeysSinceLastRehash == 0), aa.newKeysSinceLastRehash.to!string); +aa.rehash(); +assert((aa.numRehashes == 2), aa.numRehashes.to!string); + +auto realAA = cast(int[string])aa; +assert("abc" in realAA); +assert("def" in realAA); + +auto alsoRealAA = aa.aaOf; +assert("ghi" in realAA); +assert("jkl" !in realAA); + +auto aa2 = aa.dup; +aa2["jkl"] = 123; +assert("jkl" in aa2); +assert("jkl" !in aa);
Returns the length of the internal associative array.
The length of the internal associative array.
Bumps the internal counter of new keys since the last rehash, and depending + on the resulting value of it, maybe rehashes.
true if the associative array was rehashed; false if not.
The minimum number of additions needed before the first rehash takes place.
The number of new entries that has been added since the last rehash. Accessor.
The number of new entries that has been added since the last rehash.
The number of times this instance has rehashed itself. Accessor.
The number of times this instance has rehashed itself.
Delegate called when rehashing takes place.
Inherit a native associative array into aa.
Other associative array.
Wraps key in aa to the internal associative array.
A pointer to the value of the key passed, or null if it isn't in + the associative array
Allows for casting this into the base associative array type.
Assigns a value into the internal associative array. If it created a new + entry, then call maybeRehash to bump the internal counter and maybe rehash.
Rehashes the internal associative array, bumping the rehash counter and + zeroing the keys-added counter. Additionally invokes the onRehashDg delegate.
A reference to the rehashed internal array.
The modifier by how much more entries must be added before another rehash + takes place, with regards to the current aa length.
A multiplier of 2.0 means the associative array will be rehashed as + soon as its length doubles in size. Must be more than 1.
Removes a key from the aa associative array by merely + invoking .remove.
Constructor.
Associative arary to inherit. Taken by reference for now.
Containers.
Simple buffer/queue for storing and fetching items of any type T. + Does not use manual memory allocation.
Simple circular-ish buffer for storing items of type T that discards elements + when the maximum size is reached. Does not use manual memory allocation.
An associative array and a Mutex. Wraps associative + array operations in mutex locks.
A wrapper around a native associative array that you can controllably set to + automatically rehash as entries are added.
1 { +2 Buffer!string buffer; +3 +4 buffer.put("abc"); +5 buffer.put("def"); +6 assert(!buffer.empty); +7 assert(buffer.front == "abc"); +8 buffer.popFront(); +9 assert(buffer.front == "def"); +10 buffer.popFront(); +11 assert(buffer.empty); +12 } +13 { +14 Buffer!(char, Yes.dynamic, 3) buffer; +15 +16 assert(!buffer.buf.length); +17 buffer ~= 'a'; +18 assert(buffer.buf.length == 3); +19 buffer ~= 'b'; +20 buffer ~= 'c'; +21 assert(buffer.length == 3); +22 buffer ~= 'd'; +23 assert(buffer.buf.length > 3); +24 assert(buffer[0..5] == "abcd"); +25 buffer.clear(); +26 assert(buffer.empty); +27 } +28 { +29 RehashingAA!(int[string]) aa; +30 aa.minimumNeededForRehash = 2; +31 +32 aa["abc"] = 123; +33 aa["def"] = 456; +34 assert((aa.newKeysSinceLastRehash == 2), aa.newKeysSinceLastRehash.to!string); +35 assert((aa.numRehashes == 0), aa.numRehashes.to!string); +36 aa["ghi"] = 789; +37 assert((aa.numRehashes == 1), aa.numRehashes.to!string); +38 assert((aa.newKeysSinceLastRehash == 0), aa.newKeysSinceLastRehash.to!string); +39 aa.rehash(); +40 assert((aa.numRehashes == 2), aa.numRehashes.to!string); +41 +42 auto realAA = cast(int[string])aa; +43 assert("abc" in realAA); +44 assert("def" in realAA); +45 +46 auto alsoRealAA = aa.aaOf; +47 assert("ghi" in realAA); +48 assert("jkl" !in realAA); +49 +50 auto aa2 = aa.dup; +51 aa2["jkl"] = 123; +52 assert("jkl" in aa2); +53 assert("jkl" !in aa); +54 } +55 { +56 MutexedAA!(string[int]) aa; +57 aa.setup(); // important! +58 +59 aa[1] = "one"; +60 aa[2] = "two"; +61 aa[3] = "three"; +62 +63 auto hasOne = aa.has(1); +64 assert(hasOne); +65 assert(aa[1] == "one"); +66 +67 assert(aa[2] == "two"); +68 +69 auto three = aa.get(3); +70 assert(three == "three"); +71 +72 auto four = aa.get(4, "four"); +73 assert(four == "four"); +74 +75 auto five = aa.require(5, "five"); +76 assert(five == "five"); +77 assert(aa[5] == "five"); +78 +79 auto keys = aa.keys; +80 assert(keys.canFind(1)); +81 assert(keys.canFind(5)); +82 assert(!keys.canFind(6)); +83 +84 auto values = aa.values; +85 assert(values.canFind("one")); +86 assert(values.canFind("four")); +87 assert(!values.canFind("six")); +88 +89 aa.rehash(); +90 }
Takes the member of an enum by string and returns that enum member.
It lowers to a big switch of the enum member strings. It is faster than + std.conv.to and generates less template bloat. However, it does not work + with enums where multiple members share the same values, as the big switch + ends up getting duplicate cases.
Taken from: https://forum.dlang.org/post/bfnwstkafhfgihavtzsz@forum.dlang.org + written by Stephan Koch (https://github.com/UplinkCoder). + Used with permission.
the string name of an enum member.
The enum member whose name matches the enumstring string (not whose + *value* matches the string).
ConvException if no matching enum member with the + passed name could be found.
Does not work with enums that have members with duplicate values.
enum SomeEnum { one, two, three }; + +SomeEnum foo = Enum!SomeEnum.fromString("one"); +SomeEnum bar = Enum!SomeEnum.fromString("three"); + +assert(foo == SomeEnum.one); +assert(bar == SomeEnum.three);
Template housing optimised functions to get the string name of an enum + member, or the enum member of a name string.
std.conv.to is typically the go-to for this job; however it quickly bloats + the binary and is not performant on larger enums.
Takes the member of an enum by string and returns that enum member.
The inverse of fromString, this function takes an enum member value + and returns its string identifier.
enum to base this template on.
import std.conv : ConvException; +import std.exception : assertThrown; + +enum T +{ + UNSET, + QUERY, + PRIVMSG, + RPL_ENDOFMOTD +} + +with (T) +{ + static assert(Enum!T.fromString("QUERY") == QUERY); + static assert(Enum!T.fromString("PRIVMSG") == PRIVMSG); + static assert(Enum!T.fromString("RPL_ENDOFMOTD") == RPL_ENDOFMOTD); + static assert(Enum!T.fromString("UNSET") == UNSET); + assertThrown!ConvException(Enum!T.fromString("DOESNTEXIST")); // needs @system +} + +with (T) +{ + static assert(Enum!T.toString(QUERY) == "QUERY"); + static assert(Enum!T.toString(PRIVMSG) == "PRIVMSG"); + static assert(Enum!T.toString(RPL_ENDOFMOTD) == "RPL_ENDOFMOTD"); +}
The inverse of fromString, this function takes an enum member value + and returns its string identifier.
It lowers to a big switch of the enum members. It is faster than + std.conv.to and generates less template bloat.
Taken from: https://forum.dlang.org/post/bfnwstkafhfgihavtzsz@forum.dlang.org + written by Stephan Koch (https://github.com/UplinkCoder). + Used with permission.
Enum member whose string name we want.
The string name of the passed enum member.
enum SomeEnum { one, two, three }; + +string foo = Enum!SomeEnum.toString(one); +assert(foo == "one");
Convenience wrapper around Enum that infers the type of the passed enum member.
Enum member whose string name we want.
The string name of the passed enum member.
enum T +{ + UNSET, + QUERY, + PRIVMSG, + RPL_ENDOFMOTD +} + +with (T) +{ + static assert(enumToString(QUERY) == "QUERY"); + static assert(enumToString(PRIVMSG) == "PRIVMSG"); + static assert(enumToString(RPL_ENDOFMOTD) == "RPL_ENDOFMOTD"); +}
This module contains functions that in one way or another converts its + arguments into something else.
Credit for Enum goes to Stephan Koch (https://github.com/UplinkCoder).
Convenience wrapper around Enum that infers the type of the passed enum member.
Returns the decimal value of a hex number in string form.
Convenience wrapper that takes a hex string and populates a Voldemort + struct with its RR, GG and BB components.
Translates an integer into an alphanumeric string. Assumes ASCII. + Overload that returns the string.
Translates an integer into an alphanumeric string. Assumes ASCII. + Overload that takes an output range sink.
Template housing optimised functions to get the string name of an enum + member, or the enum member of a name string.
Returns the decimal value of a hex number in string form.
Hexadecimal number in string form.
Flag of whether or not to accept rrggbb in lowercase form.
An integer equalling the value of the passed hexadecimal string.
ConvException if the hex string was malformed.
int fifteen = numFromHex("F"); +int twofiftyfive = numFromHex("FF");
Convenience wrapper that takes a hex string and populates a Voldemort + struct with its RR, GG and BB components.
This is to be used when mapping a #RRGGBB colour to their decimal + red/green/blue equivalents.
Hexadecimal number (colour) in string form.
Whether or not to accept the rrggbb string in + lowercase letters.
A Voldemort struct with r, g and b members,
import std.conv : text; +{ + auto rgb = rgbFromHex("000102"); + + assert((rgb.r == 0), rgb.r.text); + assert((rgb.g == 1), rgb.g.text); + assert((rgb.b == 2), rgb.b.text); +} +{ + auto rgb = rgbFromHex("#FFFFFF"); + + assert((rgb.r == 255), rgb.r.text); + assert((rgb.g == 255), rgb.g.text); + assert((rgb.b == 255), rgb.b.text); +} +{ + auto rgb = rgbFromHex("#3C507D"); + + assert((rgb.r == 60), rgb.r.text); + assert((rgb.g == 80), rgb.b.text); + assert((rgb.b == 125), rgb.b.text); +} +{ + auto rgb = rgbFromHex("9a4B7c", Yes.acceptLowercase); + + assert((rgb.r == 154), rgb.r.text); + assert((rgb.g == 75), rgb.g.text); + assert((rgb.b == 124), rgb.b.text); +}
Translates an integer into an alphanumeric string. Assumes ASCII. + Overload that returns the string.
Merely leverages toAlphaInto.
The maximum number of digits to expect input of.
The minimum amount of leading zeroes to include in the + output, mirroring the format specifier "%0nd".
Integer to translate into string.
The passed integer num in string form.
int num = 12345; +string asString = num.toAlpha; +assert(asString == "12345"); +assert(asString == num.to!string);
{ + enum num = 123_456; + immutable translated = num.toAlpha; + assert((translated == "123456"), translated); +} +{ + enum num = 0; + immutable translated = num.toAlpha; + assert((translated == "0"), translated); +} +{ + enum num = 999; + immutable translated = num.toAlpha; + assert((translated == "999"), translated); +} +{ + enum num = -987; + immutable translated = num.toAlpha; + assert((translated == "-987"), translated); +} +{ + enum num = 123; + immutable translated = num.toAlpha!(12, 6); + assert((translated == "000123"), translated); +} +{ + enum num = -1; + immutable translated = num.toAlpha!(3, 3); + assert((translated == "-001"), translated); +} +{ + enum num = -123_456_789_012_345L; + immutable translated = num.toAlpha!15; + assert((translated == "-123456789012345"), translated); +} +{ + enum num = long.min; + immutable translated = num.toAlpha; + assert((translated == "-9223372036854775808"), translated); +}
Translates an integer into an alphanumeric string. Assumes ASCII. + Overload that takes an output range sink.
The maximum number of digits to expect input of.
The minimum amount of leading zeroes to include in the + output, mirroring the format specifier "%0nd".
Integer to translate into string.
Output range sink.
Appender!(char[]) sink; +int num = 12345; +num.toAlphaInto(sink); +assert(sink.data == "12345"); +assert(sink.data == num.to!string);
import std.array : Appender; + +Appender!(char[]) sink; + +{ + enum num = 123_456; + num.toAlphaInto(sink); + assert((sink.data == "123456"), sink.data); + sink.clear(); +} +{ + enum num = 0; + num.toAlphaInto(sink); + assert((sink.data == "0"), sink.data); + sink.clear(); +} +{ + enum num = 999; + num.toAlphaInto(sink); + assert((sink.data == "999"), sink.data); + sink.clear(); +} +{ + enum num = -987; + num.toAlphaInto(sink); + assert((sink.data == "-987"), sink.data); + sink.clear(); +} +{ + enum num = 123; + num.toAlphaInto!(12, 6)(sink); + assert((sink.data == "000123"), sink.data); + sink.clear(); +} +{ + enum num = -1; + num.toAlphaInto!(3, 3)(sink); + assert((sink.data == "-001"), sink.data); + sink.clear(); +} +{ + enum num = -123_456_789_012_345L; + num.toAlphaInto!15(sink); + assert((sink.data == "-123456789012345"), sink.data); + sink.clear(); +} +{ + enum num = long.min; + num.toAlphaInto(sink); + assert((sink.data == "-9223372036854775808"), sink.data); + //sink.clear(); +}
Constructs statement lines for each changed field (or the delta) between two + instances of a struct and stores them into a passed output sink.
Whether or not to build assert statements or assignment statements.
Output buffer to write to.
Original struct object.
Changed struct object.
The number of tabs to indent the lines with.
The string name of a recursing symbol, if applicable.
struct Foo +{ + string s; + int i; + bool b; +} + +Foo altered; + +altered.s = "some string"; +altered.i = 42; +altered.b = true; + +Appender!(char[]) sink; +sink.formatDeltaInto!(No.asserts)(Foo.init, altered);
1 import lu.uda : Hidden; +2 import std.array : Appender; +3 +4 Appender!(char[]) sink; +5 sink.reserve(1024); +6 +7 struct Server +8 { +9 string address; +10 ushort port; +11 bool connected; +12 } +13 +14 struct Connection +15 { +16 enum State +17 { +18 unset, +19 disconnected, +20 connected, +21 } +22 +23 State state; +24 string nickname; +25 @Hidden string user; +26 @Hidden string password; +27 Server server; +28 } +29 +30 Connection conn; +31 +32 with (conn) +33 { +34 state = Connection.State.connected; +35 nickname = "NICKNAME"; +36 user = "USER"; +37 password = "hunter2"; +38 server.address = "address.tld"; +39 server.port = 1337; +40 } +41 +42 sink.formatDeltaInto!(No.asserts)(Connection.init, conn, 0, "conn"); +43 +44 assert(sink.data == +45 `conn.state = Connection.State.connected; +46 conn.nickname = "NICKNAME"; +47 conn.server.address = "address.tld"; +48 conn.server.port = 1337; +49 `, '\n' ~ sink.data); +50 +51 sink = typeof(sink).init; +52 +53 sink.formatDeltaInto!(Yes.asserts)(Connection.init, conn, 0, "conn"); +54 +55 assert(sink.data == +56 `assert((conn.state == Connection.State.connected), Enum!(Connection.State).toString(conn.state)); +57 assert((conn.nickname == "NICKNAME"), conn.nickname); +58 assert((conn.server.address == "address.tld"), conn.server.address); +59 assert((conn.server.port == 1337), conn.server.port.to!string); +60 `, '\n' ~ sink.data); +61 +62 struct Foo +63 { +64 string s; +65 int i; +66 bool b; +67 char c; +68 } +69 +70 Foo f1; +71 f1.s = "string"; +72 f1.i = 42; +73 f1.b = true; +74 f1.c = '$'; +75 +76 Foo f2 = f1; +77 f2.s = "yarn"; +78 f2.b = false; +79 f2.c = '#'; +80 +81 sink = typeof(sink).init; +82 +83 sink.formatDeltaInto!(No.asserts)(f1, f2); +84 assert(sink.data == +85 `s = "yarn"; +86 b = false; +87 c = '#'; +88 `, '\n' ~ sink.data); +89 +90 sink = typeof(sink).init; +91 +92 sink.formatDeltaInto!(Yes.asserts)(f1, f2); +93 assert(sink.data == +94 `assert((s == "yarn"), s); +95 assert(!b); +96 assert((c == '#'), c.to!string); +97 `, '\n' ~ sink.data); +98 +99 sink = typeof(sink).init; +100 +101 { +102 struct S +103 { +104 int i; +105 } +106 +107 class C +108 { +109 string s; +110 bool b; +111 S child; +112 } +113 +114 C c1 = new C; +115 C c2 = new C; +116 +117 c2.s = "harbl"; +118 c2.b = true; +119 c2.child.i = 42; +120 +121 sink.formatDeltaInto!(No.asserts)(c1, c2); +122 assert(sink.data == +123 `s = "harbl"; +124 b = true; +125 child.i = 42; +126 `, '\n' ~ sink.data); +127 +128 sink = typeof(sink).init; +129 +130 sink.formatDeltaInto!(Yes.asserts)(c1, c2); +131 assert(sink.data == +132 `assert((s == "harbl"), s); +133 assert(b); +134 assert((child.i == 42), child.i.to!string); +135 `, '\n' ~ sink.data); +136 } +137 { +138 struct Blah +139 { +140 int[5] arr; +141 string[3] sarr; +142 char[2] carr; +143 } +144 +145 Blah b1; +146 Blah b2; +147 b2.arr = [ 1, 0, 3, 0, 5 ]; +148 b2.sarr = [ "hello", string.init, "world" ]; +149 b2.carr = [ 'a', char.init ]; +150 +151 sink = typeof(sink).init; +152 +153 sink.formatDeltaInto(b1, b2); +154 assert(sink.data == +155 `arr[0] = 1; +156 arr[2] = 3; +157 arr[4] = 5; +158 sarr[0] = "hello"; +159 sarr[2] = "world"; +160 carr[0] = 'a'; +161 `); +162 +163 sink = typeof(sink).init; +164 +165 sink.formatDeltaInto!(Yes.asserts)(b1, b2); +166 assert(sink.data == +167 `assert((arr[0] == 1), arr[0].to!string); +168 assert((arr[2] == 3), arr[2].to!string); +169 assert((arr[4] == 5), arr[4].to!string); +170 assert((sarr[0] == "hello"), sarr[0]); +171 assert((sarr[2] == "world"), sarr[2]); +172 assert((carr[0] == 'a'), carr[0].to!string); +173 `); +174 }
Functions used to generate strings of statements describing the differences + (or delta) between two instances of a struct or class of the same type. + They can be either assignment statements or assert statements.
UDA conveying that this member contains sensitive information and should not + be printed in clear text; e.g. passwords.
Constructs statement lines for each changed field (or the delta) between two + instances of a struct and stores them into a passed output sink.
struct Foo +{ + string s; + int i; + bool b; +} + +Foo altered; + +altered.s = "some string"; +altered.i = 42; +altered.b = true; + +Appender!(char[]) sink; + +// Fill with delta between `Foo.init` and modified `altered` +sink.formatDeltaInto!(No.asserts)(Foo.init, altered); + +assert(sink.data == +`s = "some string"; +i = 42; +b = true; +`); +sink.clear(); + +// Do the same but prepend the name "altered" to the member names +sink.formatDeltaInto!(No.asserts)(Foo.init, altered, 0, "altered"); + +assert(sink.data == +`altered.s = "some string"; +altered.i = 42; +altered.b = true; +`); +sink.clear(); + +// Generate assert statements instead, for easy copy/pasting into unittest blocks +sink.formatDeltaInto!(Yes.asserts)(Foo.init, altered, 0, "altered"); + +assert(sink.data == +`assert((altered.s == "some string"), altered.s); +assert((altered.i == 42), altered.i.to!string); +assert(altered.b, altered.b.to!string); +`);
lu is a general purpose library, doing a little bit of everything.
It complements the standard library and is not a replacement for it.
Simple array utilities.
Functionality generic enough to be used in several places.
Containers.
This module contains functions that in one way or another converts its + arguments into something else.
Functions used to generate strings of statements describing the differences + (or delta) between two instances of a struct or class of the same type. + They can be either assignment statements or assert statements.
This module contains the meldInto functions; functions that take two + structs or classes of the same type and combine them, creating a resulting + object with the union of the members of both parents. Array and associative + array variants exist too.
Functions and templates that do numeric calculations or other manipulation, + in some way or another.
This module contains functions that in some way or another manipulates + struct and class instances, as well as (associative) arrays.
SemVer information about the current release.
Various functions related to serialising and deserialising structs into/from + .ini-like files.
String manipulation functions complementing the standard library.
Various compile-time traits and cleverness.
Type constructors.
Common user-defined attributes (UDAs).
Strategy in which to sort object-type JSON keys when we format/serialise + the stored storage to string.
Value | Meaning |
---|---|
passthrough | Order is as JSONValue.toPrettyString + formats it. |
sorted | Sorted by key. |
reverse | Reversely sorted by key. |
inGivenOrder | Keys are listed in the order given in a passed string[] array. Actual keys not present in the array are not included in the output, + and keys not existing yet present in the array are added as empty. |
A wrapped JSONValue with helper functions.
Strategy in which to sort object-type JSON keys when we format/serialise + the stored storage to string.
Loads JSON from disk.
Initialises and clears the JSONValue, preparing + it for object storage.
Saves the JSON storage to disk. Formatting is done as specified by the + passed KeyOrderStrategy argument.
Formats an object-type JSON storage into an output range sink.
Formats an object-type JSON storage into an output range sink.
The underlying JSONValue storage of this JSONStorage.
JSONStorage s; + +s.reset(); // not always necessary + +s.storage["foo"] = null; // JSONValue quirk +s.storage["foo"]["abc"] = JSONValue(42); +s.storage["foo"]["def"] = JSONValue(3.14f); +s.storage["foo"]["ghi"] = JSONValue([ "bar", "baz", "qux" ]); +s.storage["bar"] = JSONValue("asdf"); + +assert(s.storage.length == 2);
import std.conv : text; +import std.json : JSONValue; + +JSONStorage s; +s.reset(); + +s.storage["key"] = null; +s.storage["key"]["subkey1"] = "abc"; +s.storage["key"]["subkey2"] = "def"; +s.storage["key"]["subkey3"] = "ghi"; +assert((s.storage["key"].object.length == 3), s.storage["key"].object.length.text); + +s.storage["foo"] = null; +s.storage["foo"]["arr"] = JSONValue([ "blah "]); +s.storage["foo"]["arr"].array ~= JSONValue("bluh"); +assert((s.storage["foo"]["arr"].array.length == 2), s.storage["foo"]["arr"].array.length.text);
Loads JSON from disk.
In the case where the file doesn't exist or is otherwise invalid, then + JSONValue is initialised to null (by way of + JSONStorage.reset).
Filename of file to read from.
Whatever readText and/or + parseJSON throws.
lu.common.FileTypeMismatchException if the filename exists + but is not a file.
Initialises and clears the JSONValue, preparing + it for object storage.
Saves the JSON storage to disk. Formatting is done as specified by the + passed KeyOrderStrategy argument.
Merely leverages serialiseInto and writeln.
Key order strategy in which to sort object-type JSON keys.
Filename of the file to save to.
The order in which object-type keys should be listed in + the output file. Non-existent keys are represented as empty. Not + specified keys are omitted.
Formats an object-type JSON storage into an output range sink.
Top-level keys are sorted as per the passed KeyOrderStrategy. This + overload is specialised for KeyOrderStrategy.inGivenOrder.
Order strategy in which to sort top-level keys.
Output sink to fill with formatted output.
The order in which object-type keys should be listed in + the output file. Non-existent keys are represented as empty. + Not specified keys are omitted.
Formats an object-type JSON storage into an output range sink.
Top-level keys are sorted as per the passed KeyOrderStrategy. This + overload is specialised for strategies other than + KeyOrderStrategy.inGivenOrder, and as such takes one parameter fewer.
Order strategy in which to sort top-level keys.
Output sink to fill with formatted output.
1 import std.array : Appender; +2 import std.json; +3 +4 JSONStorage this_; +5 Appender!(char[]) sink; +6 +7 // Original JSON +8 this_.storage = parseJSON( +9 `{ +10 "#abc": +11 { +12 "hirrsteff" : "o", +13 "foobar" : "v" +14 }, +15 "#def": +16 { +17 "harrsteff": "v", +18 "flerpeloso" : "o" +19 }, +20 "#zzz": +21 { +22 "asdf" : "v" +23 } +24 }`); +25 +26 // KeyOrderStrategy.passthrough +27 this_.serialiseInto!(KeyOrderStrategy.passthrough)(sink); +28 assert((sink.data == +29 `{ +30 "#abc": { +31 "foobar": "v", +32 "hirrsteff": "o" +33 }, +34 "#def": { +35 "flerpeloso": "o", +36 "harrsteff": "v" +37 }, +38 "#zzz": { +39 "asdf": "v" +40 } +41 }`), '\n' ~ sink.data); +42 sink.clear(); +43 +44 // KeyOrderStrategy.sorted +45 this_.serialiseInto!(KeyOrderStrategy.sorted)(sink); +46 assert((sink.data == +47 `{ +48 "#abc": { +49 "foobar": "v", +50 "hirrsteff": "o" +51 }, +52 "#def": { +53 "flerpeloso": "o", +54 "harrsteff": "v" +55 }, +56 "#zzz": { +57 "asdf": "v" +58 } +59 }`), '\n' ~ sink.data); +60 sink.clear(); +61 +62 // KeyOrderStrategy.reverse +63 this_.serialiseInto!(KeyOrderStrategy.reverse)(sink); +64 assert((sink.data == +65 `{ +66 "#zzz": { +67 "asdf": "v" +68 }, +69 "#def": { +70 "flerpeloso": "o", +71 "harrsteff": "v" +72 }, +73 "#abc": { +74 "foobar": "v", +75 "hirrsteff": "o" +76 } +77 }`), '\n' ~ sink.data); +78 sink.clear(); +79 +80 // KeyOrderStrategy.inGivenOrder +81 this_.serialiseInto!(KeyOrderStrategy.inGivenOrder)(sink, [ "#def", "#abc", "#foo", "#fighters" ]); +82 assert((sink.data == +83 `{ +84 "#def": { +85 "flerpeloso": "o", +86 "harrsteff": "v" +87 }, +88 "#abc": { +89 "foobar": "v", +90 "hirrsteff": "o" +91 }, +92 "#foo": {}, +93 "#fighters": {} +94 }`), '\n' ~ sink.data); +95 sink.clear(); +96 +97 // Empty JSONValue +98 JSONStorage this2; +99 this2.serialiseInto(sink); +100 assert((sink.data == +101 `{}`), '\n' ~ sink.data); +102
The underlying JSONValue storage of this JSONStorage.
Recursively populates a passed associative or dynamic array with the + contents of a JSONValue.
A wrapped JSONValue with helper functions.
JSONStorage json; +assert(json.storage.type == JSONType.null_); + +json.load("somefile.json"); +assert(json.storage.type == JSONType.object); + +json.serialiseInto!(JSONStorage.KeyOrderStrategy.inGivenOrder) + (stdout.lockingTextWriter, [ "foo", "bar", "baz" ]); + +// Printed to screen, regardless how `.toPrettyString` would have ordered it: +/* + { + "foo": { + 1, + 2, + }, + "bar": { + 3, + 4, + }, + "baz": { + 5, + 6, + } + } +*/ + +// Prints keys in sorted order. +json.serialiseInto!(JSONStorage.KeyOrderStrategy.sorted)(stdout.lockingTextWriter) + +// Use a [std.array.Appender|Appender] to serialise into a string. + +// Adding and removing values still needs the same dance as with std.json. +// Room for future improvement. +json.storage["qux"] = null; +json.storage["qux"].array = null; +json.storage["qux"].array ~= 7; +json.storage["qux"].array ~= 8; + +json.save("somefile.json");
Recursively populates a passed associative or dynamic array with the + contents of a JSONValue.
This is used where we want to store information on disk but keep it in + memory without the overhead of dealing with JSONValues.
Note: This only works with JSONValues that conform to + arrays and associative arrays, not such that mix element/value types.
Reference to target array or associative array to write to.
Source JSONValue to sync the contents with.
Whether or not to save string keys in lowercase.
Whether or not to save final string values in lowercase.
1 import std.json : JSONType, JSONValue; +2 +3 { +4 long[string] aa = +5 [ +6 "abc" : 123, +7 "def" : 456, +8 "ghi" : 789, +9 ]; +10 +11 JSONValue j = JSONValue(aa); +12 typeof(aa) fromJSON; +13 +14 foreach (immutable key, const value; j.objectNoRef) +15 { +16 fromJSON[key] = value.integer; +17 } +18 +19 assert(aa == fromJSON); // not is +20 +21 auto aaCopy = aa.dup; +22 +23 aa["jlk"] = 12; +24 assert(aa != fromJSON); +25 +26 aa = typeof(aa).init; +27 populateFromJSON(aa, j); +28 assert(aa == aaCopy); +29 } +30 { +31 auto aa = +32 [ +33 "abc" : true, +34 "def" : false, +35 "ghi" : true, +36 ]; +37 +38 JSONValue j = JSONValue(aa); +39 typeof(aa) fromJSON; +40 +41 foreach (immutable key, const value; j.objectNoRef) +42 { +43 if (value.type == JSONType.true_) fromJSON[key] = true; +44 else if (value.type == JSONType.false_) fromJSON[key] = false; +45 else +46 { +47 assert(0); +48 } +49 } +50 +51 assert(aa == fromJSON); // not is +52 +53 auto aaCopy = aa.dup; +54 +55 aa["jkl"] = false; +56 assert(aa != fromJSON); +57 +58 aa = typeof(aa).init; +59 populateFromJSON(aa, j); +60 assert(aa == aaCopy); +61 } +62 { +63 auto arr = [ "abc", "def", "ghi", "jkl" ]; +64 +65 JSONValue j = JSONValue(arr); +66 typeof(arr) fromJSON; +67 +68 foreach (const value; j.arrayNoRef) +69 { +70 fromJSON ~= value.str; +71 } +72 +73 assert(arr == fromJSON); // not is +74 +75 auto arrCopy = arr.dup; +76 +77 arr[0] = "no"; +78 assert(arr != arrCopy); +79 +80 arr = []; +81 populateFromJSON(arr, j); +82 assert(arr == arrCopy); +83 } +84 { +85 auto aa = +86 [ +87 "abc" : [ "def", "ghi", "jkl" ], +88 "def" : [ "MNO", "PQR", "STU" ], +89 ]; +90 +91 JSONValue j = JSONValue(aa); +92 typeof(aa)fromJSON; +93 +94 foreach (immutable key, const arrJSON; j.objectNoRef) +95 { +96 foreach (const entry; arrJSON.arrayNoRef) +97 { +98 fromJSON[key] ~= entry.str; +99 } +100 } +101 +102 assert(aa == fromJSON); // not is +103 +104 auto aaCopy = aa.dup; +105 aaCopy["abc"] = aa["abc"].dup; +106 +107 aa["abc"][0] = "no"; +108 aa["ghi"] ~= "VWXYZ"; +109 assert(aa != fromJSON); +110 +111 aa = typeof(aa).init; +112 populateFromJSON(aa, j); +113 assert(aa == aaCopy); +114 } +115 { +116 int[3] arr = [ 1, 2, 3 ]; +117 +118 JSONValue j = JSONValue(arr); +119 +120 int[3] arr2; +121 arr2.populateFromJSON(j); +122 assert(arr2 == arr); +123 }
To what extent a source should overwrite a target when melding.
Value | Meaning |
---|---|
conservative | Takes care not to overwrite settings when either the source or the + target is .init. |
aggressive | Only considers the init-ness of the source, so as not to overwrite + things with empty strings, but otherwise always considers the source to + trump the target. |
overwriting | Works like aggressive but also always overwrites bools, regardless of + falseness. |
UDA conveying that this member's value cannot or should not be melded.
This module contains the meldInto functions; functions that take two + structs or classes of the same type and combine them, creating a resulting + object with the union of the members of both parents. Array and associative + array variants exist too.
To what extent a source should overwrite a target when melding.
UDA conveying that this member's value cannot or should not be melded.
Takes two structs or classes of the same type and melds them together, + making the members a union of the two.
Takes two arrays and melds them together, making a union of the two.
Takes two associative arrays and melds them together, making a union of the two.
struct Foo +{ + string abc; + string def; + int i; + float f; + double d; +} + +Foo f1; // = new Foo; +f1.abc = "ABC"; +f1.def = "DEF"; + +Foo f2; // = new Foo; +f2.abc = "this won't get copied"; +f2.def = "neither will this"; +f2.i = 42; +f2.f = 3.14f; + +f2.meldInto(f1); + +with (f1) +{ + import std.math : isNaN; + + assert(abc == "ABC"); + assert(def == "DEF"); + assert(i == 42); + assert(f == 3.14f); + assert(d.isNaN); +}
Takes two structs or classes of the same type and melds them together, + making the members a union of the two.
In the case of classes it only overwrites members in intoThis that are + typeof(member).init, so only unset members get their values overwritten by + the melding class. It also does not work with static members.
In the case of structs it also overwrites members that still have their + default values, in cases where such is applicable.
Supply a template parameter MeldingStrategy to decide to which extent + values are overwritten.
To what extent the source object should overwrite set + (non-init) values in the receiving object.
Object to meld (source).
Reference to object to meld (target).
struct Foo +{ + string abc; + int def; + bool b = true; +} + +Foo foo, bar; +foo.abc = "from foo" +foo.b = false; +bar.def = 42; +foo.meldInto(bar); + +assert(bar.abc == "from foo"); +assert(bar.def == 42); +assert(!bar.b); // false overwrote default value true
1 import std.conv : to; +2 +3 static struct TestFoo +4 { +5 string abc; +6 string def; +7 int i; +8 float f; +9 double d; +10 int[string] aa; +11 int[] arr; +12 int* ip; +13 +14 void blah() {} +15 +16 const string kek; +17 immutable bool bur; +18 +19 this(bool bur) +20 { +21 kek = "uden lo"; +22 this.bur = bur; +23 } +24 } +25 +26 TestFoo f1; // = new TestFoo; +27 f1.abc = "ABC"; +28 f1.def = "DEF"; +29 f1.aa = [ "abc" : 123, "ghi" : 789 ]; +30 f1.arr = [ 1, 0, 3, 0, 5 ]; +31 +32 TestFoo f2; // = new TestFoo; +33 f2.abc = "this won't get copied"; +34 f2.def = "neither will this"; +35 f2.i = 42; +36 f2.f = 3.14f; +37 f2.aa = [ "abc" : 999, "def" : 456 ]; +38 f2.arr = [ 0, 2, 0, 4 ]; +39 +40 f2.meldInto(f1); +41 +42 with (f1) +43 { +44 import std.math : isNaN; +45 +46 assert((abc == "ABC"), abc); +47 assert((def == "DEF"), def); +48 assert((i == 42), i.to!string); +49 assert((f == 3.14f), f.to!string); +50 assert(d.isNaN, d.to!string); +51 assert((aa == [ "abc" : 123, "def" : 456, "ghi" : 789 ]), aa.to!string); +52 assert((arr == [ 1, 2, 3, 4, 5 ]), arr.to!string); +53 } +54 +55 TestFoo f3; // new TestFoo; +56 f3.abc = "abc"; +57 f3.def = "def"; +58 f3.i = 100_135; +59 f3.f = 99.9f; +60 f3.aa = [ "abc" : 123, "ghi" : 789 ]; +61 f3.arr = [ 1, 0, 3, 0, 5 ]; +62 +63 TestFoo f4; // new TestFoo; +64 f4.abc = "OVERWRITTEN"; +65 f4.def = "OVERWRITTEN TOO"; +66 f4.i = 0; +67 f4.f = 0.1f; +68 f4.d = 99.999; +69 f4.aa = [ "abc" : 999, "def" : 456 ]; +70 f4.arr = [ 9, 2, 0, 4 ]; +71 +72 f4.meldInto!(MeldingStrategy.aggressive)(f3); +73 +74 with (f3) +75 { +76 static if (__VERSION__ >= 2091) +77 { +78 import std.math : isClose; +79 } +80 else +81 { +82 import std.math : approxEqual; +83 alias isClose = approxEqual; +84 } +85 +86 assert((abc == "OVERWRITTEN"), abc); +87 assert((def == "OVERWRITTEN TOO"), def); +88 assert((i == 100_135), i.to!string); // 0 is int.init +89 assert((f == 0.1f), f.to!string); +90 assert(isClose(d, 99.999), d.to!string); +91 assert((aa == [ "abc" : 999, "def" : 456, "ghi" : 789 ]), aa.to!string); +92 assert((arr == [ 9, 2, 3, 4, 5 ]), arr.to!string); +93 } +94 +95 // Overwriting is just aggressive but always overwrites bools. +96 +97 struct User +98 { +99 enum Class { anyone, blacklist, whitelist, admin } +100 string nickname; +101 string alias_; +102 string ident; +103 string address; +104 string login; +105 bool special; +106 Class class_; +107 } +108 +109 User one; +110 with (one) +111 { +112 nickname = "foobar"; +113 ident = "NaN"; +114 address = "herpderp.net"; +115 special = false; +116 class_ = User.Class.whitelist; +117 } +118 +119 User two; +120 with (two) +121 { +122 nickname = "foobar^"; +123 alias_ = "FooBar"; +124 address = "asdf.org"; +125 login = "kamelusu"; +126 special = true; +127 class_ = User.Class.blacklist; +128 } +129 +130 //import lu.conv : Enum; +131 +132 User twoCopy = two; +133 +134 one.meldInto!(MeldingStrategy.conservative)(two); +135 with (two) +136 { +137 assert((nickname == "foobar^"), nickname); +138 assert((alias_ == "FooBar"), alias_); +139 assert((ident == "NaN"), ident); +140 assert((address == "asdf.org"), address); +141 assert((login == "kamelusu"), login); +142 assert(special); +143 assert(class_ == User.Class.whitelist);//, Enum!(User.Class).toString(class_)); +144 } +145 +146 one.class_ = User.Class.blacklist; +147 +148 one.meldInto!(MeldingStrategy.overwriting)(twoCopy); +149 with (twoCopy) +150 { +151 assert((nickname == "foobar"), nickname); +152 assert((alias_ == "FooBar"), alias_); +153 assert((ident == "NaN"), ident); +154 assert((address == "herpderp.net"), address); +155 assert((login == "kamelusu"), login); +156 assert(!special); +157 assert(class_ == User.Class.blacklist);//, Enum!(User.Class).toString(class_)); +158 } +159 +160 struct EnumThing +161 { +162 enum Enum { unset, one, two, three } +163 Enum enum_; +164 } +165 +166 EnumThing e1; +167 EnumThing e2; +168 e2.enum_ = EnumThing.Enum.three; +169 assert(e1.enum_ == EnumThing.Enum.init);//, Enum!(EnumThing.Enum).toString(e1.enum_)); +170 e2.meldInto(e1); +171 assert(e1.enum_ == EnumThing.Enum.three);//, Enum!(EnumThing.Enum).toString(e1.enum_)); +172 +173 struct WithArray +174 { +175 string[] arr; +176 } +177 +178 WithArray w1, w2; +179 w1.arr = [ "arr", "matey", "I'ma" ]; +180 w2.arr = [ "pirate", "stereotype", "unittest" ]; +181 w2.meldInto(w1); +182 assert((w1.arr == [ "arr", "matey", "I'ma", "pirate", "stereotype", "unittest" ]), w1.arr.to!string); +183 +184 WithArray w3, w4; +185 w3.arr = [ "arr", "matey", "I'ma" ]; +186 w4.arr = [ "arr", "matey", "I'ma" ]; +187 w4.meldInto(w3); +188 assert((w3.arr == [ "arr", "matey", "I'ma" ]), w3.arr.to!string); +189 +190 struct Server +191 { +192 string address; +193 } +194 +195 struct Bot +196 { +197 string nickname; +198 Server server; +199 } +200 +201 Bot b1, b2; +202 b1.nickname = "foobar"; +203 b1.server.address = "freenode.net"; +204 +205 assert(!b2.nickname.length, b2.nickname); +206 assert(!b2.server.address.length, b2.nickname); +207 b1.meldInto(b2); +208 assert((b2.nickname == "foobar"), b2.nickname); +209 assert((b2.server.address == "freenode.net"), b2.server.address); +210 +211 b2.nickname = "harbl"; +212 b2.server.address = "rizon.net"; +213 +214 b2.meldInto!(MeldingStrategy.aggressive)(b1); +215 assert((b1.nickname == "harbl"), b1.nickname); +216 assert((b1.server.address == "rizon.net"), b1.server.address); +217 +218 class Class +219 { +220 static int i; +221 string s; +222 bool b; +223 } +224 +225 Class abc = new Class; +226 abc.i = 42; +227 abc.s = "some string"; +228 abc.b = true; +229 +230 Class def = new Class; +231 def.s = "other string"; +232 abc.meldInto(def); +233 +234 assert((def.i == 42), def.i.to!string); +235 assert((def.s == "other string"), def.s); +236 assert(def.b); +237 +238 abc.meldInto!(MeldingStrategy.aggressive)(def); +239 assert((def.s == "some string"), def.s); +240 +241 struct Bools +242 { +243 bool a = true; +244 bool b = false; +245 } +246 +247 Bools bools1, bools2, inverted, backupInverted; +248 +249 bools2.a = false; +250 +251 inverted.a = false; +252 inverted.b = true; +253 backupInverted = inverted; +254 +255 bools2.meldInto(bools1); +256 assert(!bools1.a); +257 assert(!bools1.b); +258 +259 bools2.meldInto(inverted); +260 assert(!inverted.a); +261 assert(inverted.b); +262 inverted = backupInverted; +263 +264 bools2.meldInto!(MeldingStrategy.overwriting)(inverted); +265 assert(!inverted.a); +266 assert(!inverted.b); +267 inverted = backupInverted; +268 +269 struct Asdf +270 { +271 string nickname = "sadf"; +272 string server = "asdf.net"; +273 } +274 +275 Asdf a, b; +276 a.server = "a"; +277 b.server = "b"; +278 b.meldInto!(MeldingStrategy.aggressive)(a); +279 assert((a.server == "b"), a.server); +280 +281 a.server = "a"; +282 b.server = Asdf.init.server; +283 b.meldInto!(MeldingStrategy.aggressive)(a); +284 assert((a.server == "a"), a.server); +285 +286 struct Blah +287 { +288 int yes = 42; +289 @Unmeldable int no = 24; +290 } +291 +292 Blah blah1, blah2; +293 blah1.yes = 5; +294 blah1.no = 42; +295 blah1.meldInto!(MeldingStrategy.aggressive)(blah2); +296 assert((blah2.yes == 5), blah2.yes.to!string); +297 assert((blah2.no == 24), blah2.no.to!string);
Takes two arrays and melds them together, making a union of the two.
It only overwrites members that are T.init, so only unset + fields get their values overwritten by the melding array. Supply a + template parameter MeldingStrategy.aggressive to make it overwrite if the + melding array's field is not T.init. Furthermore use + MeldingStrategy.overwriting if working with bool members.
To what extent the source object should overwrite set + (non-init) values in the receiving object.
Array to meld (source).
Reference to the array to meld (target).
int[] arr1 = [ 1, 2, 3, 0, 0, 0 ]; +int[] arr2 = [ 0, 0, 0, 4, 5, 6 ]; +arr1.meldInto!(MeldingStrategy.conservative)(arr2); + +assert(arr2 == [ 1, 2, 3, 4, 5, 6 ]);
import std.conv : to; + +auto arr1 = [ 123, 0, 789, 0, 456, 0 ]; +auto arr2 = [ 0, 456, 0, 123, 0, 789 ]; +arr1.meldInto!(MeldingStrategy.conservative)(arr2); +assert((arr2 == [ 123, 456, 789, 123, 456, 789 ]), arr2.to!string); + +auto yarr1 = [ 'Z', char.init, 'Z', char.init, 'Z' ]; +auto yarr2 = [ 'A', 'B', 'C', 'D', 'E', 'F' ]; +yarr1.meldInto!(MeldingStrategy.aggressive)(yarr2); +assert((yarr2 == [ 'Z', 'B', 'Z', 'D', 'Z', 'F' ]), yarr2.to!string); + +auto harr1 = [ char.init, 'X' ]; +yarr1.meldInto(harr1); +assert((harr1 == [ 'Z', 'X', 'Z', char.init, 'Z' ]), harr1.to!string); + +char[5] harr2 = [ '1', '2', '3', '4', '5' ]; +char[] harr3; +harr2.meldInto(harr3); +assert((harr2 == harr3), harr3.to!string); + +int[3] asdf; +int[3] hasdf; +asdf.meldInto(hasdf); + +int[] dyn = new int[2]; +int[3] stat; +dyn.meldInto(stat);
Takes two associative arrays and melds them together, making a union of the two.
This is largely the same as the array-version meldInto but doesn't need + the extensive template constraints it employs, so it might as well be kept separate.
To what extent the source object should overwrite set + (non-init) values in the receiving object.
Associative array to meld (source).
Reference to the associative array to meld (target).
int[string] aa1 = [ "abc" : 42, "def" : -1 ]; +int[string] aa2 = [ "ghi" : 10, "jkl" : 7 ]; +arr1.meldInto(arr2); + +assert("abc" in aa2); +assert("def" in aa2); +assert("ghi" in aa2); +assert("jkl" in aa2);
bool[string] aa1; +bool[string] aa2; + +aa1["a"] = true; +aa1["b"] = false; +aa2["c"] = true; +aa2["d"] = false; + +assert("a" in aa1); +assert("b" in aa1); +assert("c" in aa2); +assert("d" in aa2); + +aa1.meldInto!(MeldingStrategy.overwriting)(aa2); + +assert("a" in aa2); +assert("b" in aa2); + +string[string] saa1; +string[string] saa2; + +saa1["a"] = "a"; +saa1["b"] = "b"; +saa2["c"] = "c"; +saa2["d"] = "d"; + +saa1.meldInto!(MeldingStrategy.conservative)(saa2); +assert("a" in saa2); +assert("b" in saa2); + +saa1["a"] = "A"; +saa1.meldInto!(MeldingStrategy.aggressive)(saa2); +assert(saa2["a"] == "A");
Given a number, calculate the largest multiple of n needed to reach that number.
It rounds up, and if supplied Yes.alwaysOneUp it will always overshoot. + This is good for when calculating format pattern widths.
Number to reach.
Base value to find a multiplier for.
Whether or not to always overshoot.
The multiple of n that reaches and possibly overshoots num.
immutable width = 15.getMultipleOf(4); +assert(width == 16); +immutable width2 = 16.getMultipleOf(4, Yes.alwaysOneUp); +assert(width2 == 20);
import std.conv : text; + +immutable n1 = 15.getMultipleOf(4); +assert((n1 == 16), n1.text); + +immutable n2 = 16.getMultipleOf(4, Yes.alwaysOneUp); +assert((n2 == 20), n2.text); + +immutable n3 = 16.getMultipleOf(4); +assert((n3 == 16), n3.text); +immutable n4 = 0.getMultipleOf(5); +assert((n4 == 0), n4.text); + +immutable n5 = 1.getMultipleOf(1); +assert((n5 == 1), n5.text); + +immutable n6 = 1.getMultipleOf(1, Yes.alwaysOneUp); +assert((n6 == 2), n6.text); + +immutable n7 = 5.getMultipleOf(5, Yes.alwaysOneUp); +assert((n7 == 6), n7.text); + +immutable n8 = 5L.getMultipleOf(5L, Yes.alwaysOneUp); +assert((n8 == 6L), n8.text); + +immutable n9 = 5UL.getMultipleOf(5UL, No.alwaysOneUp); +assert((n9 == 5UL), n9.text); + +immutable n10 = (5.0).getMultipleOf(5UL, Yes.alwaysOneUp); +assert((n10 == (6.0)), n10.text);
Functions and templates that do numeric calculations or other manipulation, + in some way or another.
Given a number, calculate the largest multiple of n needed to reach that number.
Exception, to be thrown when setMemberByName fails for some given reason.
It is a normal Exception but with attached strings of + the type name, name of member and the value that was attempted to set.
Create a new SetMemberException, without attaching anything.
Create a new SetMemberException, attaching extra set-member information.
Name of the member that was attempted to set.
Name of type that was attempted to set the member of.
String representation of the value that was attempted to assign.
Name of the member that was attempted to set.
Create a new SetMemberException, without attaching anything.
Create a new SetMemberException, attaching extra set-member information.
Name of type that was attempted to set the member of.
String representation of the value that was attempted to assign.
This module contains functions that in some way or another manipulates + struct and class instances, as well as (associative) arrays.
Exception, to be thrown when setMemberByName fails for some given reason.
Iterates an associative array and deletes invalid entries, either if the value + is in a default .init state or as per the optionally passed predicate.
Inspects a passed struct or class for members whose values match that of the + passed token. Matches members are set to a replacement value, which is + an optional parameter that defaults to the .init value of the token's type.
Given a struct/class object, sets one of its members by its string name to a + specified value. Overload that takes the value as a string and tries to + convert it into the target type.
Given a struct/class object, sets one of its members by its string name to a + specified value. Overload that takes a value of the same type as the target + member, rather than a string to convert. Integer promotion applies.
UDA conveying that the annotated array should have this token as separator + when formatted to a string.
struct Foo +{ + string nickname; + string address; +} + +Foo foo; + +foo.setMemberByName("nickname", "foobar"); +foo.setMemberByName("address", "subdomain.address.tld"); + +assert(foo.nickname == "foobar"); +assert(foo.address == "subdomain.address.tld"); + +foo.replaceMembers("subdomain.address.tld", "foobar"); +assert(foo.address == "foobar"); + +foo.replaceMembers("foobar", string.init); +assert(foo.nickname.length == 0); +assert(foo.address.length == 0);
Iterates an associative array and deletes invalid entries, either if the value + is in a default .init state or as per the optionally passed predicate.
It is supposedly undefined behaviour to remove an associative array's fields + when foreaching through it. So far we have been doing a simple mark-sweep + garbage collection whenever we encounter this use-case in the code, so why + not just make a generic solution instead and deduplicate code?
Optional predicate if special logic is needed to determine whether + an entry is to be removed or not.
The associative array to modify.
auto aa = +[ + "abc" : "def", + "ghi" : string.init; + "mno" : "123", + "pqr" : string.init, +]; + +pruneAA(aa); + +assert("ghi" !in aa); +assert("pqr" !in aa); + +pruneAA!((entry) => entry.length > 0)(aa); + +assert("abc" !in aa); +assert("mno" !in aa);
1 import std.conv : text; +2 +3 { +4 auto aa = +5 [ +6 "abc" : "def", +7 "ghi" : "jkl", +8 "mno" : "123", +9 "pqr" : string.init, +10 ]; +11 +12 pruneAA!((a) => a == "def")(aa); +13 assert("abc" !in aa); +14 +15 pruneAA!((a,b) => a == "pqr")(aa); +16 assert("pqr" !in aa); +17 +18 pruneAA!`a == "123"`(aa); +19 assert("mno" !in aa); +20 } +21 { +22 struct Record +23 { +24 string name; +25 int id; +26 } +27 +28 auto aa = +29 [ +30 "rhubarb" : Record("rhubarb", 100), +31 "raspberry" : Record("raspberry", 80), +32 "blueberry" : Record("blueberry", 0), +33 "apples" : Record("green apples", 60), +34 "yakisoba" : Record("yakisoba", 78), +35 "cabbage" : Record.init, +36 ]; +37 +38 pruneAA(aa); +39 assert("cabbage" !in aa); +40 +41 pruneAA!((entry) => entry.id < 80)(aa); +42 assert("blueberry" !in aa); +43 assert("apples" !in aa); +44 assert("yakisoba" !in aa); +45 assert((aa.length == 2), aa.length.text); +46 } +47 { +48 import std.algorithm.searching : canFind; +49 +50 string[][string] aa = +51 [ +52 "abc" : [ "a", "b", "c" ], +53 "def" : [ "d", "e", "f" ], +54 "ghi" : [ "g", "h", "i" ], +55 "jkl" : [ "j", "k", "l" ], +56 ]; +57 +58 pruneAA(aa); +59 assert((aa.length == 4), aa.length.text); +60 +61 pruneAA!((entry) => entry.canFind("a"))(aa); +62 assert("abc" !in aa); +63 }
Inspects a passed struct or class for members whose values match that of the + passed token. Matches members are set to a replacement value, which is + an optional parameter that defaults to the .init value of the token's type.
Whether or not to recurse into aggregate members.
Reference to a struct or class whose members to iterate over.
What value to look for in members, be it a string or an integer + or whatever; anything that can be compared to.
What to assign matched values. Defaults to the .init + of the matched type.
1 struct Bar +2 { +3 string s = "content"; +4 } +5 +6 struct Foo +7 { +8 Bar b; +9 string s = "more content"; +10 } +11 +12 Foo foo1, foo2; +13 foo1.replaceMembers("-"); +14 assert(foo1 == foo2); +15 +16 foo2.s = "-"; +17 foo2.replaceMembers("-"); +18 assert(!foo2.s.length); +19 foo2.b.s = "-"; +20 foo2.replaceMembers!(Yes.recurse)("-", "herblp"); +21 assert((foo2.b.s == "herblp"), foo2.b.s); +22 +23 Foo foo3; +24 foo3.s = "---"; +25 foo3.b.s = "---"; +26 foo3.replaceMembers!(No.recurse)("---"); +27 assert(!foo3.s.length); +28 assert((foo3.b.s == "---"), foo3.b.s); +29 foo3.replaceMembers!(Yes.recurse)("---"); +30 assert(!foo3.b.s.length); +31 +32 class Baz +33 { +34 string barS = "init"; +35 string barT = "*"; +36 Foo f; +37 } +38 +39 Baz b1 = new Baz; +40 Baz b2 = new Baz; +41 +42 b1.replaceMembers("-"); +43 assert((b1.barS == b2.barS), b1.barS); +44 assert((b1.barT == b2.barT), b1.barT); +45 +46 b1.replaceMembers("*"); +47 assert(b1.barS.length, b1.barS); +48 assert(!b1.barT.length, b1.barT); +49 assert(b1.f.s.length, b1.f.s); +50 +51 b1.replaceMembers!(Yes.recurse)("more content"); +52 assert(!b1.f.s.length, b1.f.s); +53 +54 import std.conv : to; +55 +56 struct Qux +57 { +58 int i = 42; +59 } +60 +61 Qux q; +62 +63 q.replaceMembers("*"); +64 assert(q.i == 42); +65 +66 q.replaceMembers(43); +67 assert(q.i == 42); +68 +69 q.replaceMembers(42, 99); +70 assert((q.i == 99), q.i.to!string); +71 +72 struct Flerp +73 { +74 string[] arr; +75 } +76 +77 Flerp flerp; +78 flerp.arr = [ "-" ]; +79 assert(flerp.arr.length == 1); +80 flerp.replaceMembers("-"); +81 assert(!flerp.arr.length);
Given a struct/class object, sets one of its members by its string name to a + specified value. Overload that takes the value as a string and tries to + convert it into the target type.
It does not currently recurse into other struct/class members.
Reference object whose members to set.
String name of the thing's member to set.
String contents of the value to set the member to; string + even if the member is of a different type.
true if a member was found and set, false if nothing was done.
ConvException if a string could not be + converted into an array, if a passed string could not be converted into + a bool, or if std.conv.to failed to convert a string into wanted type T. + SetMemberException if an unexpected exception was thrown.
struct Foo +{ + string name; + int number; + bool alive; +} + +Foo foo; + +foo.setMemberByName("name", "James Bond"); +foo.setMemberByName("number", "007"); +foo.setMemberByName("alive", "false"); + +assert(foo.name == "James Bond"); +assert(foo.number == 7); +assert(!foo.alive);
1 import lu.uda : Separator; +2 import std.conv : to; +3 +4 struct Foo +5 { +6 string bar; +7 int baz; +8 float* f; +9 string[string] aa; +10 +11 @Separator("|") +12 @Separator(" ") +13 { +14 string[] arr; +15 string[] matey; +16 } +17 +18 @Separator(";;") +19 { +20 string[] parrots; +21 string[] withSpaces; +22 } +23 +24 @Separator(`\o/`) +25 { +26 string[] blurgh; +27 } +28 +29 static if (__VERSION__ >= 2087L) +30 { +31 @(`\o/`) +32 { +33 int[] blargh; +34 } +35 } +36 } +37 +38 Foo foo; +39 bool success; +40 +41 success = foo.setMemberByName("bar", "asdf fdsa adf"); +42 assert(success); +43 assert((foo.bar == "asdf fdsa adf"), foo.bar); +44 +45 success = foo.setMemberByName("baz", "42"); +46 assert(success); +47 assert((foo.baz == 42), foo.baz.to!string); +48 +49 success = foo.setMemberByName("aa", `["abc":"def", "ghi":"jkl"]`); +50 assert(success); +51 assert((foo.aa == [ "abc":"def", "ghi":"jkl" ]), foo.aa.to!string); +52 +53 success = foo.setMemberByName("arr", "herp|derp|dirp|darp"); +54 assert(success); +55 assert((foo.arr == [ "herp", "derp", "dirp", "darp"]), foo.arr.to!string); +56 +57 success = foo.setMemberByName("arr", "herp derp dirp|darp"); +58 assert(success); +59 assert((foo.arr == [ "herp", "derp", "dirp", "darp"]), foo.arr.to!string); +60 +61 success = foo.setMemberByName("matey", "this,should,not,be,separated"); +62 assert(success); +63 assert((foo.matey == [ "this,should,not,be,separated" ]), foo.matey.to!string); +64 +65 success = foo.setMemberByName("parrots", "squaawk;;parrot sounds;;repeating"); +66 assert(success); +67 assert((foo.parrots == [ "squaawk", "parrot sounds", "repeating"]), +68 foo.parrots.to!string); +69 +70 success = foo.setMemberByName("withSpaces", ` squoonk ;;" spaced ";;" "`); +71 assert(success); +72 assert((foo.withSpaces == [ "squoonk", ` spaced `, " "]), +73 foo.withSpaces.to!string); +74 +75 success = foo.setMemberByName("invalid", "oekwpo"); +76 assert(!success); +77 +78 /*success = foo.setMemberByName("", "true"); +79 assert(!success);*/ +80 +81 success = foo.setMemberByName("matey", "hirr steff\\ stuff staff\\|stirf hooo"); +82 assert(success); +83 assert((foo.matey == [ "hirr", "steff stuff", "staff|stirf", "hooo" ]), foo.matey.to!string); +84 +85 success = foo.setMemberByName("matey", "hirr steff\\\\ stuff staff\\\\|stirf hooo"); +86 assert(success); +87 assert((foo.matey == [ "hirr", "steff\\", "stuff", "staff\\", "stirf", "hooo" ]), foo.matey.to!string); +88 +89 success = foo.setMemberByName("matey", "asdf\\ fdsa\\\\ hirr steff"); +90 assert(success); +91 assert((foo.matey == [ "asdf fdsa\\", "hirr", "steff" ]), foo.matey.to!string); +92 +93 success = foo.setMemberByName("blurgh", "asdf\\\\o/fdsa\\\\\\o/hirr\\o/\\o/\\o/\\o/\\o/\\o/\\o/\\o/steff"); +94 assert(success); +95 assert((foo.blurgh == [ "asdf\\o/fdsa\\", "hirr", "steff" ]), foo.blurgh.to!string); +96 +97 static if (__VERSION__ >= 2087L) +98 { +99 success = foo.setMemberByName("blargh", `1\o/2\o/3\o/4\o/5`); +100 assert(success); +101 assert((foo.blargh == [ 1, 2, 3, 4, 5 ]), foo.blargh.to!string); +102 } +103 +104 class C +105 { +106 string abc; +107 int def; +108 } +109 +110 C c = new C; +111 +112 success = c.setMemberByName("abc", "this is abc"); +113 assert(success); +114 assert((c.abc == "this is abc"), c.abc); +115 +116 success = c.setMemberByName("def", "42"); +117 assert(success); +118 assert((c.def == 42), c.def.to!string); +119 +120 import lu.conv : Enum; +121 +122 enum E { abc, def, ghi } +123 +124 struct S +125 { +126 E e = E.ghi; +127 } +128 +129 S s; +130 +131 assert(s.e == E.ghi); +132 success = s.setMemberByName("e", "def"); +133 assert(success); +134 assert((s.e == E.def), Enum!E.toString(s.e)); +135 +136 struct StructWithOpAssign +137 { +138 string thing = "init"; +139 +140 void opAssign(const string thing) +141 { +142 this.thing = thing; +143 } +144 } +145 +146 StructWithOpAssign assignable; +147 assert((assignable.thing == "init"), assignable.thing); +148 assignable = "new thing"; +149 assert((assignable.thing == "new thing"), assignable.thing); +150 +151 struct StructWithAssignableMember +152 { +153 StructWithOpAssign child; +154 } +155 +156 StructWithAssignableMember parent; +157 success = parent.setMemberByName("child", "flerp"); +158 assert(success); +159 assert((parent.child.thing == "flerp"), parent.child.thing); +160 +161 class ClassWithOpAssign +162 { +163 string thing = "init"; +164 +165 void opAssign(const string thing) //@safe pure nothrow @nogc +166 { +167 this.thing = thing; +168 } +169 } +170 +171 class ClassWithAssignableMember +172 { +173 ClassWithOpAssign child; +174 +175 this() +176 { +177 child = new ClassWithOpAssign; +178 } +179 } +180 +181 ClassWithAssignableMember parent2 = new ClassWithAssignableMember; +182 success = parent2.setMemberByName("child", "flerp"); +183 assert(success); +184 assert((parent2.child.thing == "flerp"), parent2.child.thing);
Given a struct/class object, sets one of its members by its string name to a + specified value. Overload that takes a value of the same type as the target + member, rather than a string to convert. Integer promotion applies.
It does not currently recurse into other struct/class members.
Reference object whose members to set.
String name of the thing's member to set.
Value, of the same type as the target member.
true if a member was found and set, false if not.
SetMemberException if the passed valueToSet was not the same type + (or implicitly convertible to) the member to set.
struct Foo +{ + int i; + double d; +} + +Foo foo; + +foo.setMemberByName("i", 42); +foo.setMemberByName("d", 3.14); + +assert(foo.i == 42); +assert(foo.d = 3.14);
import std.conv : to; +import std.exception : assertThrown; + +struct Foo +{ + string s; + int i; + bool b; + const double d; +} + +Foo foo; + +bool success; + +success = foo.setMemberByName("s", "harbl"); +assert(success); +assert((foo.s == "harbl"), foo.s); + +success = foo.setMemberByName("i", 42); +assert(success); +assert((foo.i == 42), foo.i.to!string); + +success = foo.setMemberByName("b", true); +assert(success); +assert(foo.b); + +success = foo.setMemberByName("d", 3.14); +assert(!success); + +assertThrown!SetMemberException(foo.setMemberByName("b", 3.14));
Pre-release SemVer subversion of this build.
SemVer information about the current release.
Contains only definitions, no code. Helps importing projects tell what + features are available.
SemVer versioning of this build.
Pre-release SemVer subversion of this build.
Exception, to be thrown when the specified serialised text could not be + parsed, for whatever reason.
Create a new DeserialisationException.
Create a new DeserialisationException.
The format pattern used to format the array this struct + refers to. This is separator-specific.
enum arrayPattern = "%-(%s" ~ separator ~ "%)";
The escaped form of separator.
enum escapedSeparator = '\\' ~ separator;
Summary of UDAs that an array to be serialised is annotated with.
UDAs do not persist across function calls, so they must be summarised + (such as in a struct like this) and separately passed, at compile-time or runtime.
The format pattern used to format the array this struct + refers to. This is separator-specific.
The escaped form of separator.
Whether or not the member was annotated with a Separator.
Whether or not the member was annotated Unserialisable.
Whether or not the member was annotated with a Separator.
Whether or not the member was annotated Unserialisable.
Takes an input range containing serialised entry-value text and applies the + contents therein to one or more passed struct/class objects.
Input range from which to read the serialised text.
Out reference of an associative array of string arrays + of expected entries that were missing.
Out reference of an associative array of string arrays + of unexpected entries that did not belong.
Reference variadic list of one or more objects to apply the + deserialised values to.
DeserialisationException if there were bad lines.
struct Foo +{ + // ... +} + +struct Bar +{ + // ... +} + +Foo foo; +Bar bar; + +string[][string] missingEntries; +string[][string] invalidEntries; + +string fromFile = readText("configuration.conf"); + +fromFile + .splitter("\n") + .deserialise(missingEntries, invalidEntries, foo, bar);
1 import lu.uda : Separator; +2 import std.algorithm.iteration : splitter; +3 import std.conv : text; +4 +5 struct FooSettings +6 { +7 enum Bar { blaawp = 5, oorgle = -1 } +8 int i; +9 string s; +10 bool b; +11 float f; +12 double d; +13 Bar bar; +14 string commented; +15 string slashed; +16 int missing; +17 //bool invalid; +18 +19 @Separator(",") +20 { +21 int[] ia; +22 string[] sa; +23 bool[] ba; +24 float[] fa; +25 double[] da; +26 Bar[] bara; +27 } +28 } +29 +30 enum serialisedFileContents = +31 `[Foo] +32 i 42 +33 ia 1,2,-3,4,5 +34 s hello world! +35 sa hello,world,! +36 b true +37 ba true,false,true +38 invalid name +39 +40 # comment +41 ; other type of comment +42 // third type of comment +43 +44 f 3.14 #hirp +45 fa 0.0,1.1,-2.2,3.3 ;herp +46 d 99.9 //derp +47 da 99.9999,0.0001,-1 +48 bar oorgle +49 bara blaawp,oorgle,blaawp +50 #commented hi +51 // slashed also commented +52 invalid ho +53 +54 [DifferentSection] +55 ignored completely +56 because no DifferentSection struct was passed +57 nil 5 +58 naN !"¤%&/`; +59 +60 string[][string] missing; +61 string[][string] invalid; +62 +63 FooSettings foo; +64 serialisedFileContents +65 .splitter("\n") +66 .deserialise(missing, invalid, foo); +67 +68 with (foo) +69 { +70 assert((i == 42), i.text); +71 assert((ia == [ 1, 2, -3, 4, 5 ]), ia.text); +72 assert((s == "hello world!"), s); +73 assert((sa == [ "hello", "world", "!" ]), sa.text); +74 assert(b); +75 assert((ba == [ true, false, true ]), ba.text); +76 assert((f == 3.14f), f.text); +77 assert((fa == [ 0.0f, 1.1f, -2.2f, 3.3f ]), fa.text); +78 assert((d == 99.9), d.text); +79 +80 static if (__VERSION__ >= 2091) +81 { +82 import std.math : isClose; +83 } +84 else +85 { +86 import std.math : approxEqual; +87 alias isClose = approxEqual; +88 } +89 +90 // rounding errors with LDC on Windows +91 assert(isClose(da[0], 99.9999), da[0].text); +92 assert(isClose(da[1], 0.0001), da[1].text); +93 assert(isClose(da[2], -1.0), da[2].text); +94 +95 with (FooSettings.Bar) +96 { +97 assert((bar == oorgle), bar.text); +98 assert((bara == [ blaawp, oorgle, blaawp ]), bara.text); +99 } +100 } +101 +102 import std.algorithm.searching : canFind; +103 +104 assert("Foo" in missing); +105 assert(missing["Foo"].canFind("missing")); +106 assert(!missing["Foo"].canFind("commented")); +107 assert(!missing["Foo"].canFind("slashed")); +108 assert("Foo" in invalid); +109 assert(invalid["Foo"].canFind("invalid")); +110 +111 struct DifferentSection +112 { +113 string ignored; +114 string because; +115 int nil; +116 string naN; +117 } +118 +119 // Can read other structs from the same file +120 +121 DifferentSection diff; +122 serialisedFileContents +123 .splitter("\n") +124 .deserialise(missing, invalid, diff); +125 +126 with (diff) +127 { +128 assert((ignored == "completely"), ignored); +129 assert((because == "no DifferentSection struct was passed"), because); +130 assert((nil == 5), nil.text); +131 assert((naN == `!"¤%&/`), naN); +132 } +133 +134 enum Letters { abc, def, ghi, } +135 +136 struct Struct +137 { +138 Letters lt = Letters.def; +139 } +140 +141 enum configContents = +142 `[Struct] +143 lt ghi +144 `; +145 Struct st; +146 configContents +147 .splitter("\n") +148 .deserialise(missing, invalid, st); +149 +150 assert(st.lt == Letters.ghi); +151 +152 class Class +153 { +154 enum Bar { blaawp = 5, oorgle = -1 } +155 int i; +156 string s; +157 bool b; +158 float f; +159 double d; +160 Bar bar; +161 string omitted; +162 +163 @Separator(",") +164 { +165 int[] ia; +166 string[] sa; +167 bool[] ba; +168 float[] fa; +169 double[] da; +170 Bar[] bara; +171 } +172 } +173 +174 enum serialisedFileContentsClass = +175 `[Class] +176 i 42 +177 ia 1,2,-3,4,5 +178 s hello world! +179 sa hello,world,! +180 b true +181 ba true,false,true +182 wrong name +183 +184 # comment +185 ; other type of comment +186 // third type of comment +187 +188 f 3.14 #hirp +189 fa 0.0,1.1,-2.2,3.3 ;herp +190 d 99.9 //derp +191 da 99.9999,0.0001,-1 +192 bar oorgle +193 bara blaawp,oorgle,blaawp`; +194 +195 Class c = new Class; +196 serialisedFileContentsClass +197 .splitter("\n") +198 .deserialise(missing, invalid, c); +199 +200 with (c) +201 { +202 assert((i == 42), i.text); +203 assert((ia == [ 1, 2, -3, 4, 5 ]), ia.text); +204 assert((s == "hello world!"), s); +205 assert((sa == [ "hello", "world", "!" ]), sa.text); +206 assert(b); +207 assert((ba == [ true, false, true ]), ba.text); +208 assert((f == 3.14f), f.text); +209 assert((fa == [ 0.0f, 1.1f, -2.2f, 3.3f ]), fa.text); +210 assert((d == 99.9), d.text); +211 +212 static if (__VERSION__ >= 2091) +213 { +214 import std.math : isClose; +215 } +216 else +217 { +218 import std.math : approxEqual; +219 alias isClose = approxEqual; +220 } +221 +222 // rounding errors with LDC on Windows +223 assert(isClose(da[0], 99.9999), da[0].text); +224 assert(isClose(da[1], 0.0001), da[1].text); +225 assert(isClose(da[2], -1.0), da[2].text); +226 +227 with (Class.Bar) +228 { +229 assert((bar == oorgle), b.text); +230 assert((bara == [ blaawp, oorgle, blaawp ]), bara.text); +231 } +232 }
Various functions related to serialising and deserialising structs into/from + .ini-like files.
Exception, to be thrown when the specified serialised text could not be + parsed, for whatever reason.
UDA conveying that this member may contain characters that would otherwise + indicate a comment, but isn't.
UDA conveying that this member's value must be quoted when serialised.
UDA conveying that a field cannot (or should not) be serialised.
Takes an input range containing serialised entry-value text and applies the + contents therein to one or more passed struct/class objects.
Takes an unformatted string of serialised entry-value text and justifies it + into two neat columns.
Convenience function to call serialise on several objects.
Serialises the fields of an object into an .ini file-like format.
Serialises a non-string array into a single row. To be used when serialising + an aggregate with serialise.
Splits a line into an entry and a value component.
UDA conveying that the annotated array should have this token as separator + when formatted to a string.
Summary of UDAs that an array to be serialised is annotated with.
struct FooSettings + { + string fooasdf; + string bar; + string bazzzzzzz; + @Quoted flerrp; + double pi; + } + + FooSettings f; + + f.fooasdf = "foo"; + f.bar = "bar"; + f.bazzzzzzz = "baz"; + f.flerrp = "hirr steff "; + f.pi = 3.14159; + + enum fooSerialised = +`[Foo] + fooasdf foo + bar bar + bazzzzzzz baz + flerrp "hirr steff " + pi 3.14159`; + + enum fooJustified = + `[Foo] + fooasdf foo + bar bar + bazzzzzzz baz + flerrp "hirr steff " + pi 3.14159`; + + Appender!(char[]) sink; + + sink.serialise(f); + assert(sink.data.justifiedEntryValueText == fooJustified); + + FooSettings mirror; + deserialise(fooSerialised, mirror); + assert(mirror == f); + + FooSettings mirror2; + deserialise(fooJustified, mirror2); + assert(mirror2 == mirror);
Takes an unformatted string of serialised entry-value text and justifies it + into two neat columns.
It does one pass through it all first to determine the maximum width of the + entry names, then another to format it and eventually return a flat string.
Unjustified raw serialised text.
.ini file-like text, justified into two columns.
struct Foo +{ + // ... +} + +struct Bar +{ + // ... +} + +Foo foo; +Bar bar; + +Appender!(char[]) sink; + +sink.serialise(foo, bar); +immutable justified = sink.data.justifiedEntryValueText;
1 import std.algorithm.iteration : splitter; +2 import std.array : Appender; +3 import lu.uda : Separator; +4 +5 struct Foo +6 { +7 enum Bar { blaawp = 5, oorgle = -1 } +8 int someInt = 42; +9 string someString = "hello world!"; +10 bool someBool = true; +11 float someFloat = 3.14f; +12 double someDouble = 99.9; +13 Bar someBars = Bar.oorgle; +14 string harbl; +15 +16 @Separator(",") +17 { +18 int[] intArray = [ 1, 2, -3, 4, 5 ]; +19 string[] stringArrayy = [ "hello", "world", "!" ]; +20 bool[] boolArray = [ true, false, true ]; +21 float[] floatArray = [ 0.0, 1.1, -2.2, 3.3 ]; +22 double[] doubleArray = [ 99.9999, 0.0001, -1.0 ]; +23 Bar[] barArray = [ Bar.blaawp, Bar.oorgle, Bar.blaawp ]; +24 string[] yarn; +25 } +26 } +27 +28 struct DifferentSection +29 { +30 string ignored = "completely"; +31 string because = " no DifferentSection struct was passed"; +32 int nil = 5; +33 string naN = `!"#¤%&/`; +34 } +35 +36 Appender!(char[]) sink; +37 sink.reserve(512); +38 Foo foo; +39 DifferentSection diff; +40 enum unjustified = +41 `[Foo] +42 someInt 42 +43 someString hello world! +44 someBool true +45 someFloat 3.14 +46 someDouble 99.9 +47 someBars oorgle +48 #harbl +49 intArray 1,2,-3,4,5 +50 stringArrayy hello,world,! +51 boolArray true,false,true +52 floatArray 0,1.1,-2.2,3.3 +53 doubleArray 99.9999,0.0001,-1 +54 barArray blaawp,oorgle,blaawp +55 #yarn +56 +57 [DifferentSection] +58 ignored completely +59 because no DifferentSection struct was passed +60 nil 5 +61 naN !"#¤%&/`; +62 +63 enum justified = +64 `[Foo] +65 someInt 42 +66 someString hello world! +67 someBool true +68 someFloat 3.14 +69 someDouble 99.9 +70 someBars oorgle +71 #harbl +72 intArray 1,2,-3,4,5 +73 stringArrayy hello,world,! +74 boolArray true,false,true +75 floatArray 0,1.1,-2.2,3.3 +76 doubleArray 99.9999,0.0001,-1 +77 barArray blaawp,oorgle,blaawp +78 #yarn +79 +80 [DifferentSection] +81 ignored completely +82 because no DifferentSection struct was passed +83 nil 5 +84 naN !"#¤%&/`; +85 +86 sink.serialise(foo, diff); +87 assert((sink.data == unjustified), '\n' ~ sink.data); +88 immutable configText = justifiedEntryValueText(sink.data.idup); +89 +90 assert((configText == justified), '\n' ~ configText);
Convenience function to call serialise on several objects.
Reference output range to write the serialised objects to (in + their .ini file-like format).
Variadic list of objects to serialise.
struct Foo +{ + // ... +} + +struct Bar +{ + // ... +} + +Foo foo; +Bar bar; + +Appender!(char[]) sink; + +sink.serialise(foo, bar); +assert(!sink.data.empty);
Serialises the fields of an object into an .ini file-like format.
It only serialises fields not annotated with + Unserialisable, and it doesn't recurse into other + structs or classes.
Reference output range to write to, usually an + Appender.
Object to serialise.
struct Foo +{ + // ... +} + +Foo foo; + +Appender!(char[]) sink; + +sink.serialise(foo); +assert(!sink.data.empty);
1 import lu.uda : Separator, Quoted; +2 import std.array : Appender; +3 +4 struct FooSettings +5 { +6 string fooasdf = "foo 1"; +7 string bar = "foo 1"; +8 string bazzzzzzz = "foo 1"; +9 @Quoted flerrp = "hirr steff "; +10 double pi = 3.14159; +11 @Separator(",") int[] arr = [ 1, 2, 3 ]; +12 @Separator(";") string[] harbl = [ "harbl;;", ";snarbl;", "dirp" ]; +13 +14 static if (__VERSION__ >= 2087L) +15 { +16 @("|") string[] matey = [ "a", "b", "c" ]; +17 } +18 } +19 +20 struct BarSettings +21 { +22 string foofdsa = "foo 2"; +23 string bar = "bar 2"; +24 string bazyyyyyyy = "baz 2"; +25 @Quoted flarrp = " hirrsteff"; +26 double pipyon = 3.0; +27 } +28 +29 static if (__VERSION__ >= 2087L) +30 { +31 enum fooSerialised = +32 `[Foo] +33 fooasdf foo 1 +34 bar foo 1 +35 bazzzzzzz foo 1 +36 flerrp "hirr steff " +37 pi 3.14159 +38 arr 1,2,3 +39 harbl harbl\;\;;\;snarbl\;;dirp +40 matey a|b|c`; +41 } +42 else +43 { +44 enum fooSerialised = +45 `[Foo] +46 fooasdf foo 1 +47 bar foo 1 +48 bazzzzzzz foo 1 +49 flerrp "hirr steff " +50 pi 3.14159 +51 arr 1,2,3 +52 harbl harbl\;\;;\;snarbl\;;dirp`; +53 } +54 +55 Appender!(char[]) fooSink; +56 fooSink.reserve(64); +57 +58 fooSink.serialise(FooSettings.init); +59 assert((fooSink.data == fooSerialised), '\n' ~ fooSink.data); +60 +61 enum barSerialised = +62 `[Bar] +63 foofdsa foo 2 +64 bar bar 2 +65 bazyyyyyyy baz 2 +66 flarrp " hirrsteff" +67 pipyon 3`; +68 +69 Appender!(char[]) barSink; +70 barSink.reserve(64); +71 +72 barSink.serialise(BarSettings.init); +73 assert((barSink.data == barSerialised), '\n' ~ barSink.data); +74 +75 // try two at once +76 Appender!(char[]) bothSink; +77 bothSink.reserve(128); +78 bothSink.serialise(FooSettings.init, BarSettings.init); +79 assert(bothSink.data == fooSink.data ~ "\n\n" ~ barSink.data); +80 +81 class C +82 { +83 int i; +84 bool b; +85 } +86 +87 C c = new C; +88 c.i = 42; +89 c.b = true; +90 +91 enum cSerialised = +92 `[C] +93 i 42 +94 b true`; +95 +96 Appender!(char[]) cSink; +97 cSink.reserve(128); +98 cSink.serialise(c); +99 assert((cSink.data == cSerialised), '\n' ~ cSink.data); +100 +101 enum Letters { abc, def, ghi, } +102 +103 struct Struct +104 { +105 Letters let = Letters.def; +106 } +107 +108 enum enumTestSerialised = +109 `[Struct] +110 let def`; +111 +112 Struct st; +113 Appender!(char[]) enumTestSink; +114 enumTestSink.serialise(st); +115 assert((enumTestSink.data == enumTestSerialised), '\n' ~ enumTestSink.data);
Serialises a non-string array into a single row. To be used when serialising + an aggregate with serialise.
Since UDAs do not persist across function calls, they must be summarised + in a SerialisationUDAs struct separately so we can pass them at runtime.
Array to serialise.
Aggregate of UDAs the original array was annotated with, passed as + a runtime value.
A string, to be saved as a serialised row in an .ini file-like format.
Splits a line into an entry and a value component.
This drop-in-replaces the regex: ^(?P<entry>[^ \t]+)[ \t]+(?P<value>.+).
String to split up.
A Voldemort struct with an entry and a value member.
{ + immutable line = "monochrome true"; + immutable result = splitEntryValue(line); + assert((result.entry == "monochrome"), result.entry); + assert((result.value == "true"), result.value); +} +{ + immutable line = "monochrome\tfalse"; + immutable result = splitEntryValue(line); + assert((result.entry == "monochrome"), result.entry); + assert((result.value == "false"), result.value); +} +{ + immutable line = "harbl "; + immutable result = splitEntryValue(line); + assert((result.entry == "harbl"), result.entry); + assert(!result.value.length, result.value); +} +{ + immutable line = "ha\t \t \t\t \t \t \tha"; + immutable result = splitEntryValue(line); + assert((result.entry == "ha"), result.entry); + assert((result.value == "ha"), result.value); +} +{ + immutable line = "#sendAfterConnect"; + immutable result = splitEntryValue(line); + assert((result.entry == "#sendAfterConnect"), result.entry); + assert(!result.value.length, result.value); +}
Returns a string of the original haystack the call to advancePast was operating on.
Exception, to be thrown when a call to advancePast went wrong.
It is a normal Exception but with an attached needle and haystack.
Create a new AdvanceExceptionImpl, without attaching anything.
Returns a string of the original haystack the call to advancePast was operating on.
Returns a string of the original needle the call to advancePast was operating on.
Returns a string of the original needle the call to advancePast was operating on.
Create a new AdvanceExceptionImpl, without attaching anything.
Raw haystack that haystack converts to string and returns.
Raw needle that needle converts to string and returns.
Returns a string of the original needle the call to advancePast was operating on.
The raw haystack (be it any kind of string), converted to a string.
Exception, to be thrown when a call to advancePast went wrong.
This is the templated implementation, so that we can support more than one + kind of needle and haystack combination.
It is a normal Exception but with an attached needle and haystack.
Create a new AdvanceExceptionImpl, without attaching anything.
Create a new AdvanceExceptionImpl, attaching a command.
Returns a string of the original needle the call to advancePast was operating on.
Returns a string of the original needle the call to advancePast was operating on.
Raw haystack that haystack converts to string and returns.
Raw needle that needle converts to string and returns.
Returns a string of the original haystack the call to advancePast was operating on.
Returns a string of the original needle the call to advancePast was operating on.
Returns a string of the original needle the call to advancePast was operating on.
The raw needle (be it any kind of string or character), converted to a string.
Create a new AdvanceExceptionImpl, without attaching anything.
Create a new AdvanceExceptionImpl, attaching a command.
The result of a call to splitInto.
Value | Meaning |
---|---|
match | The number of arguments passed the number of separated words in the input string. |
underrun | The input string did not have enough words to match the passed arguments. |
overrun | The input string had too many words and could not fit into the passed arguments. |
Given some string, finds the supplied needle token in it, returns the + string up to that point, and advances the passed string by ref to after the token.
The closest equivalent in Phobos is std.algorithm.searching.findSplit, + which largely serves the same function but doesn't advance the input string.
Additionally takes an optional Flag!"inherit" argument, to toggle + whether the return value inherits the passed line (and clearing it) upon no + needle match.
Array to walk and advance.
Token that delimits what should be returned and to where to advance. + May be another array or some individual character.
Optional flag of whether or not the whole string should be + returned and the haystack variable cleared on no needle match.
Optional file name to attach to an exception.
Optional line number to attach to an exception.
The string haystack from the start up to the needle token. The original + variable is advanced to after the token.
AdvanceException if the needle could not be found in the string.
string foobar = "foo bar!"; +string foo = foobar.advancePast(" "); +string bar = foobar.advancePast("!"); + +assert((foo == "foo"), foo); +assert((bar == "bar"), bar); +assert(!foobar.length); + +enum line = "abc def ghi"; +string def = line[4..$].advancePast(" "); // now with auto ref + +string foobar2 = "foo bar!"; +string foo2 = foobar2.advancePast(" "); +string bar2 = foobar2.advancePast("?", Yes.inherit); + +assert((foo2 == "foo"), foo2); +assert((bar2 == "bar!"), bar2); +assert(!foobar2.length); + +string slice2 = "snarfl"; +string verb2 = slice2.advancePast(" ", Yes.inherit); + +assert((verb2 == "snarfl"), verb2); +assert(!slice2.length, slice2);
1 import std.conv : to; +2 import std.string : indexOf; +3 +4 { +5 string line = "Lorem ipsum :sit amet"; +6 immutable lorem = line.advancePast(" :"); +7 assert(lorem == "Lorem ipsum", lorem); +8 assert(line == "sit amet", line); +9 } +10 { +11 string line = "Lorem ipsum :sit amet"; +12 //immutable lorem = line.advancePast(" :"); +13 immutable lorem = line.advancePast(" :"); +14 assert(lorem == "Lorem ipsum", lorem); +15 assert(line == "sit amet", line); +16 } +17 { +18 string line = "Lorem ipsum :sit amet"; +19 immutable lorem = line.advancePast(':'); +20 assert(lorem == "Lorem ipsum ", lorem); +21 assert(line == "sit amet", line); +22 } +23 { +24 string line = "Lorem ipsum :sit amet"; +25 immutable lorem = line.advancePast(':'); +26 assert(lorem == "Lorem ipsum ", lorem); +27 assert(line == "sit amet", line); +28 } +29 { +30 string line = "Lorem ipsum :sit amet"; +31 immutable lorem = line.advancePast(' '); +32 assert(lorem == "Lorem", lorem); +33 assert(line == "ipsum :sit amet", line); +34 } +35 { +36 string line = "Lorem ipsum :sit amet"; +37 immutable lorem = line.advancePast(' '); +38 assert(lorem == "Lorem", lorem); +39 assert(line == "ipsum :sit amet", line); +40 } +41 /*{ +42 string line = "Lorem ipsum :sit amet"; +43 immutable lorem = line.advancePast(""); +44 assert(!lorem.length, lorem); +45 assert(line == "Lorem ipsum :sit amet", line); +46 }*/ +47 /*{ +48 string line = "Lorem ipsum :sit amet"; +49 immutable lorem = line.advancePast(""); +50 assert(!lorem.length, lorem); +51 assert(line == "Lorem ipsum :sit amet", line); +52 }*/ +53 { +54 string line = "Lorem ipsum :sit amet"; +55 immutable lorem = line.advancePast("Lorem ipsum"); +56 assert(!lorem.length, lorem); +57 assert(line == " :sit amet", line); +58 } +59 { +60 string line = "Lorem ipsum :sit amet"; +61 immutable lorem = line.advancePast("Lorem ipsum"); +62 assert(!lorem.length, lorem); +63 assert(line == " :sit amet", line); +64 } +65 { +66 string line = "Lorem ipsum :sit amet"; +67 immutable dchar dspace = ' '; +68 immutable lorem = line.advancePast(dspace); +69 assert(lorem == "Lorem", lorem); +70 assert(line == "ipsum :sit amet", line); +71 } +72 { +73 dstring dline = "Lorem ipsum :sit amet"d; +74 immutable dspace = " "d; +75 immutable lorem = dline.advancePast(dspace); +76 assert((lorem == "Lorem"d), lorem.to!string); +77 assert((dline == "ipsum :sit amet"d), dline.to!string); +78 } +79 { +80 dstring dline = "Lorem ipsum :sit amet"d; +81 immutable wchar wspace = ' '; +82 immutable lorem = dline.advancePast(wspace); +83 assert((lorem == "Lorem"d), lorem.to!string); +84 assert((dline == "ipsum :sit amet"d), dline.to!string); +85 } +86 { +87 wstring wline = "Lorem ipsum :sit amet"w; +88 immutable wchar wspace = ' '; +89 immutable lorem = wline.advancePast(wspace); +90 assert((lorem == "Lorem"w), lorem.to!string); +91 assert((wline == "ipsum :sit amet"w), wline.to!string); +92 } +93 { +94 wstring wline = "Lorem ipsum :sit amet"w; +95 immutable wspace = " "w; +96 immutable lorem = wline.advancePast(wspace); +97 assert((lorem == "Lorem"w), lorem.to!string); +98 assert((wline == "ipsum :sit amet"w), wline.to!string); +99 } +100 { +101 string user = "foo!bar@asdf.adsf.com"; +102 user = user.advancePast('!'); +103 assert((user == "foo"), user); +104 } +105 { +106 immutable def = "abc def ghi"[4..$].advancePast(" "); +107 assert((def == "def"), def); +108 } +109 { +110 import std.exception : assertThrown; +111 assertThrown!AdvanceException("abc def ghi"[4..$].advancePast("")); +112 } +113 { +114 string line = "Lorem ipsum"; +115 immutable head = line.advancePast(" "); +116 assert((head == "Lorem"), head); +117 assert((line == "ipsum"), line); +118 } +119 { +120 string line = "Lorem"; +121 immutable head = line.advancePast(" ", Yes.inherit); +122 assert((head == "Lorem"), head); +123 assert(!line.length, line); +124 } +125 { +126 string slice = "verb"; +127 string verb; +128 +129 if (slice.indexOf(' ') != -1) +130 { +131 verb = slice.advancePast(' '); +132 } +133 else +134 { +135 verb = slice; +136 slice = string.init; +137 } +138 +139 assert((verb == "verb"), verb); +140 assert(!slice.length, slice); +141 } +142 { +143 string slice = "verb"; +144 immutable verb = slice.advancePast(' ', Yes.inherit); +145 assert((verb == "verb"), verb); +146 assert(!slice.length, slice); +147 } +148 { +149 string url = "https://google.com/index.html#fragment-identifier"; +150 url = url.advancePast('#', Yes.inherit); +151 assert((url == "https://google.com/index.html"), url); +152 } +153 { +154 string url = "https://google.com/index.html"; +155 url = url.advancePast('#', Yes.inherit); +156 assert((url == "https://google.com/index.html"), url); +157 } +158 { +159 string line = "Lorem ipsum sit amet"; +160 string[] words; +161 +162 while (line.length > 0) +163 { +164 immutable word = line.advancePast(" ", Yes.inherit); +165 words ~= word; +166 } +167 +168 assert(words == [ "Lorem", "ipsum", "sit", "amet" ]); +169 } +170 { +171 import std.exception : assertThrown; +172 string url = "https://google.com/index.html#fragment-identifier"; +173 assertThrown!AdvanceException(url.advancePast("", Yes.inherit)); +174 }
Optional flag of whether or not the whole string should be + returned and the haystack variable cleared on no needle match.
Array to walk and advance.
Token that delimits what should be returned and to where to advance. + May be another array or some individual character.
Optional file name to attach to an exception.
Optional line number to attach to an exception.
The string haystack from the start up to the needle token. The original + variable is advanced to after the token.
Checks whether or not the first letter of a string begins with any of the + passed string of characters, or single character.
Merely slices; does not decode the string and may thus give weird results on + weird inputs.
String to examine the start of, or single character.
String of characters to look for in the start of haystack, + or a single character.
true if the first character of haystack is also in needles, + false if not.
assert("#channel".beginsWithOneOf("#%+")); +assert(!"#channel".beginsWithOneOf("~%+")); +assert("".beginsWithOneOf("")); +assert("abc".beginsWithOneOf(string.init)); +assert(!"".beginsWithOneOf("abc")); + +assert("abc".beginsWithOneOf('a')); +assert(!"abc".beginsWithOneOf('b')); +assert(!"abc".beginsWithOneOf(char.init)); + +assert('#'.beginsWithOneOf("#%+")); +assert(!'#'.beginsWithOneOf("~%+")); +assert('a'.beginsWithOneOf(string.init)); +assert(!'d'.beginsWithOneOf("abc"));
Base64-decodes a string.
Merely wraps Base64.decode and + std.string.representation into one function that will work with strings.
Encoded string to decode.
A decoded normal string.
{ + immutable password = "base64:aGFyYmwgc25hcmJsIDEyMzQ1"; + immutable decoded = decode64(password[7..$]); + assert((decoded == "harbl snarbl 12345"), decoded); +} +{ + immutable password = "base64:"; + immutable decoded = decode64(password[7..$]); + assert(!decoded.length, decoded); +}
Base64-encodes a string.
Merely wraps Base64.encode and + std.string.representation into one function that will work with strings.
String line to encode.
An encoded Base64 string.
{ + immutable password = "harbl snarbl 12345"; + immutable encoded = encode64(password); + assert((encoded == "aGFyYmwgc25hcmJsIDEyMzQ1"), encoded); +} +{ + immutable string password; + immutable encoded = encode64(password); + assert(!encoded.length, encoded); +}
Replaces the control characters '\n', '\t', '\r' and '\0' with the escaped + "\\n", "\\t", "\\r" and "\\0". Does not allocate a new string if there + was nothing to escape.
String line to escape characters in.
A new string with control characters escaped, or the original one unchanged.
{ + immutable line = "abc\ndef"; + immutable expected = "abc\\ndef"; + immutable actual = escapeControlCharacters(line); + assert((actual == expected), actual); +} +{ + immutable line = "\n\t\r\0"; + immutable expected = "\\n\\t\\r\\0"; + immutable actual = escapeControlCharacters(line); + assert((actual == expected), actual); +} +{ + immutable line = ""; + immutable expected = ""; + immutable actual = escapeControlCharacters(line); + assert((actual == expected), actual); + assert(actual is line); // No string allocated +} +{ + immutable line = "nothing to escape"; + immutable expected = "nothing to escape"; + immutable actual = escapeControlCharacters(line); + assert((actual == expected), actual); + assert(actual is line); // No string allocated +}
String manipulation functions complementing the standard library.
Deprecated alias to Phobos' startsWith.
Deprecated alias to Phobos' canFind.
Compatibility alias to AdvanceException.
Compatibility alias to AdvanceExceptionImpl.
Compatibility alias to advancePast.
Exception, to be thrown when a call to advancePast went wrong.
Exception, to be thrown when a call to advancePast went wrong.
The result of a call to splitInto.
Given some string, finds the supplied needle token in it, returns the + string up to that point, and advances the passed string by ref to after the token.
Checks whether or not the first letter of a string begins with any of the + passed string of characters, or single character.
Base64-decodes a string.
Base64-encodes a string.
Replaces the control characters '\n', '\t', '\r' and '\0' with the escaped + "\\n", "\\t", "\\r" and "\\0". Does not allocate a new string if there + was nothing to escape.
Indents lines in a string with the supplied number of tabs. Returns a newly + allocated string.
Indents lines in a string into an output range sink with the supplied number of tabs.
Selects the correct singular or plural form of a word depending on the + numerical count of it.
Removes the control characters '\n', '\t', '\r' and '\0' from a string. + Does not allocate a new string if there was nothing to remove.
Splits a string by a passed separator and assign the delimited words to the + passed strings by ref.
Splits a string by a passed separator and assign the delimited words to the + passed strings by ref. Overload that stores overflow strings into a passed array.
Splits a string with on boundary as delimited by a supplied separator, into + one or more more lines not longer than the passed maximum length.
Splits a string into an array of strings by whitespace, but honours quotes.
Strips the supplied string from the end of a string.
Returns a slice of the passed string with any preceding or trailing + whitespace or linebreaks sliced off both ends. Overload that implicitly + strips " \n\r\t".
Returns a slice of the passed string with any preceding or trailing + passed characters sliced off. Implementation template capable of handling both + individual characters and strings of tokens to strip.
Returns a slice of the passed string with any preceding whitespace and/or + linebreaks sliced off. Overload that implicitly strips " \n\r\t".
Returns a slice of the passed string with any preceding passed characters + sliced off. Implementation capable of handling both individual characters + and strings of tokens to strip.
Returns a slice of the passed string with any trailing whitespace and/or + linebreaks sliced off. Overload that implicitly strips " \n\r\t".
Returns a slice of the passed string with any trailing passed characters. + Implementation template capable of handling both individual characters and + string of tokens to strip.
Returns a range of *spaces* equal to that of num tabs (\t).
Removes paired preceding and trailing tokens around a string line. + Assumes ASCII.
Removes paired preceding and trailing double quotes, unquoting a word. + Assumes ASCII.
Removes paired preceding and trailing single quotes around a line. + Assumes ASCII.
{ + string line = "Lorem ipsum :sit amet"; + immutable lorem = line.advancePast(" :"); + assert(lorem == "Lorem ipsum", lorem); + assert(line == "sit amet", line); +} +{ + string line = "Lorem ipsum :sit amet"; + immutable lorem = line.advancePast(':'); + assert(lorem == "Lorem ipsum ", lorem); + assert(line == "sit amet", line); +} +{ + string line = "Lorem ipsum sit amet"; // mutable, will be modified by ref + string[] words; + + while (line.length > 0) + { + immutable word = line.advancePast(" ", Yes.inherit); + words ~= word; + } + + assert(words == [ "Lorem", "ipsum", "sit", "amet" ]); +}
Indents lines in a string with the supplied number of tabs. Returns a newly + allocated string.
How many spaces make up a tab.
String to indent the lines of.
Amount of tabs to indent with, default 1.
How many lines to skip indenting.
A string with all the lines of the original string indented.
immutable string_ = +"Lorem ipsum +sit amet +I don't remember +any more offhand +so shrug"; + + immutable indentedOne = string_.indent; + assert((indentedOne == +" Lorem ipsum + sit amet + I don't remember + any more offhand + so shrug"), '\n' ~ indentedOne); + + immutable indentedTwo = string_.indent(2); + assert((indentedTwo == +" Lorem ipsum + sit amet + I don't remember + any more offhand + so shrug"), '\n' ~ indentedTwo); + + immutable indentedZero = string_.indent(0); + assert((indentedZero == +"Lorem ipsum +sit amet +I don't remember +any more offhand +so shrug"), '\n' ~ indentedZero); + + immutable indentedSkipTwo = string_.indent(1, 2); + assert((indentedSkipTwo == +"Lorem ipsum +sit amet + I don't remember + any more offhand + so shrug"), '\n' ~ indentedSkipTwo);
Indents lines in a string into an output range sink with the supplied number of tabs.
How many spaces in an indenting tab.
String to indent the individual lines of.
Output range to fill with the indented lines.
Optional amount of tabs to indent with, default 1.
How many lines to skip indenting.
import std.array : Appender; + + Appender!(char[]) sink; + + immutable string_ = +"Lorem ipsum +sit amet +I don't remember +any more offhand +so shrug"; + + string_.indentInto(sink); + assert((sink.data == +" Lorem ipsum + sit amet + I don't remember + any more offhand + so shrug"), '\n' ~ sink.data); + + sink.clear(); + string_.indentInto!3(sink, 2); + assert((sink.data == +" Lorem ipsum + sit amet + I don't remember + any more offhand + so shrug"), '\n' ~ sink.data); + + sink.clear(); + string_.indentInto(sink, 0); + assert((sink.data == +"Lorem ipsum +sit amet +I don't remember +any more offhand +so shrug"), '\n' ~ sink.data);
Selects the correct singular or plural form of a word depending on the + numerical count of it.
Technically works with any type provided the number is some comparable integral.
The singular if num is 1 or -1, otherwise the plural.
string one = 1.plurality("one", "two"); +string two = 2.plurality("one", "two"); +string many = (-2).plurality("one", "many"); +string many0 = 0.plurality("one", "many"); + +assert((one == "one"), one); +assert((two == "two"), two); +assert((many == "many"), many); +assert((many0 == "many"), many0);
static assert(10.plurality("one","many") == "many"); +static assert(1.plurality("one", "many") == "one"); +static assert((-1).plurality("one", "many") == "one"); +static assert(0.plurality("one", "many") == "many");
Removes the control characters '\n', '\t', '\r' and '\0' from a string. + Does not allocate a new string if there was nothing to remove.
String line to "remove" characters from.
A new string with control characters removed, or the original one unchanged.
{ + immutable line = "abc\ndef"; + immutable expected = "abcdef"; + immutable actual = removeControlCharacters(line); + assert((actual == expected), actual); +} +{ + immutable line = "\n\t\r\0"; + immutable expected = ""; + immutable actual = removeControlCharacters(line); + assert((actual == expected), actual); +} +{ + immutable line = ""; + immutable expected = ""; + immutable actual = removeControlCharacters(line); + assert((actual == expected), actual); +} +{ + immutable line = "nothing to escape"; + immutable expected = "nothing to escape"; + immutable actual = removeControlCharacters(line); + assert((actual == expected), actual); + assert(line is actual); // No new string was allocated +}
Splits a string by a passed separator and assign the delimited words to the + passed strings by ref.
Note: Does *not* take quoted substrings into consideration.
What token to separate the input string into words with.
Input string of words separated by separator.
Variadic list of strings to assign the split words in slice.
A SplitResults with the results of the split attempt.
1 import lu.conv : Enum; +2 +3 { +4 string line = "abc def ghi"; +5 string abc, def, ghi; +6 immutable results = line.splitInto(abc, def, ghi); +7 +8 assert((abc == "abc"), abc); +9 assert((def == "def"), def); +10 assert((ghi == "ghi"), ghi); +11 assert(!line.length, line); +12 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +13 } +14 { +15 string line = "abc def ghi"; +16 string abc, def, ghi; +17 immutable results = line.splitInto(abc, def, ghi); +18 +19 assert((abc == "abc"), abc); +20 assert((def == "def"), def); +21 assert((ghi == "ghi"), ghi); +22 assert(!line.length, line); +23 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +24 } +25 { +26 string line = "abc_def ghi"; +27 string abc, def, ghi; +28 immutable results = line.splitInto!"_"(abc, def, ghi); +29 +30 assert((abc == "abc"), abc); +31 assert((def == "def ghi"), def); +32 assert(!ghi.length, ghi); +33 assert(!line.length, line); +34 assert((results == SplitResults.underrun), Enum!SplitResults.toString(results)); +35 } +36 { +37 string line = "abc def ghi"; +38 string abc, def; +39 immutable results = line.splitInto(abc, def); +40 +41 assert((abc == "abc"), abc); +42 assert((def == "def"), def); +43 assert((line == "ghi"), line); +44 assert((results == SplitResults.overrun), Enum!SplitResults.toString(results)); +45 } +46 { +47 string line = "abc///def"; +48 string abc, def; +49 immutable results = line.splitInto!"//"(abc, def); +50 +51 assert((abc == "abc"), abc); +52 assert((def == "/def"), def); +53 assert(!line.length, line); +54 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +55 } +56 { +57 string line = "abc 123 def I am a fish"; +58 string abc, a123, def; +59 immutable results = line.splitInto(abc, a123, def); +60 +61 assert((abc == "abc"), abc); +62 assert((a123 == "123"), a123); +63 assert((def == "def"), def); +64 assert((line == "I am a fish"), line); +65 assert((results == SplitResults.overrun), Enum!SplitResults.toString(results)); +66 } +67 { +68 string line; +69 string abc, def; +70 immutable results = line.splitInto(abc, def); +71 assert((results == SplitResults.underrun), Enum!SplitResults.toString(results)); +72 }
Splits a string by a passed separator and assign the delimited words to the + passed strings by ref. Overload that stores overflow strings into a passed array.
Note: *Does* take quoted substrings into consideration.
What token to separate the input string into words with.
Input string of words separated by separator.
Variadic list of strings to assign the split words in slice.
Overflow array.
A SplitResults with the results of the split attempt.
1 import lu.conv : Enum; +2 import std.conv : text; +3 +4 { +5 string line = "abc def ghi"; +6 string abc, def, ghi; +7 string[] overflow; +8 immutable results = line.splitInto(abc, def, ghi, overflow); +9 +10 assert((abc == "abc"), abc); +11 assert((def == "def"), def); +12 assert((ghi == "ghi"), ghi); +13 assert(!overflow.length, overflow.text); +14 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +15 } +16 { +17 string line = "abc##def##ghi"; +18 string abc, def, ghi; +19 string[] overflow; +20 immutable results = line.splitInto!"##"(abc, def, ghi, overflow); +21 +22 assert((abc == "abc"), abc); +23 assert((def == "def"), def); +24 assert((ghi == "ghi"), ghi); +25 assert(!overflow.length, overflow.text); +26 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +27 } +28 { +29 string line = "abc def ghi"; +30 string abc, def, ghi; +31 string[] overflow; +32 immutable results = line.splitInto(abc, def, ghi, overflow); +33 +34 assert((abc == "abc"), abc); +35 assert((def == "def"), def); +36 assert((ghi == "ghi"), ghi); +37 assert(!overflow.length, overflow.text); +38 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +39 } +40 { +41 string line = "abc_def ghi"; +42 string abc, def, ghi; +43 string[] overflow; +44 immutable results = line.splitInto!"_"(abc, def, ghi, overflow); +45 +46 assert((abc == "abc"), abc); +47 assert((def == "def ghi"), def); +48 assert(!ghi.length, ghi); +49 assert(!overflow.length, overflow.text); +50 assert((results == SplitResults.underrun), Enum!SplitResults.toString(results)); +51 } +52 { +53 string line = "abc def ghi"; +54 string abc, def; +55 string[] overflow; +56 immutable results = line.splitInto(abc, def, overflow); +57 +58 assert((abc == "abc"), abc); +59 assert((def == "def"), def); +60 assert((overflow == [ "ghi" ]), overflow.text); +61 assert((results == SplitResults.overrun), Enum!SplitResults.toString(results)); +62 } +63 { +64 string line = "abc///def"; +65 string abc, def; +66 string[] overflow; +67 immutable results = line.splitInto!"//"(abc, def, overflow); +68 +69 assert((abc == "abc"), abc); +70 assert((def == "/def"), def); +71 assert(!overflow.length, overflow.text); +72 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +73 } +74 { +75 string line = "abc 123 def I am a fish"; +76 string abc, a123, def; +77 string[] overflow; +78 immutable results = line.splitInto(abc, a123, def, overflow); +79 +80 assert((abc == "abc"), abc); +81 assert((a123 == "123"), a123); +82 assert((def == "def"), def); +83 assert((overflow == [ "I", "am", "a", "fish" ]), overflow.text); +84 assert((results == SplitResults.overrun), Enum!SplitResults.toString(results)); +85 } +86 { +87 string line = `abc 123 def "I am a fish"`; +88 string abc, a123, def; +89 string[] overflow; +90 immutable results = line.splitInto(abc, a123, def, overflow); +91 +92 assert((abc == "abc"), abc); +93 assert((a123 == "123"), a123); +94 assert((def == "def"), def); +95 assert((overflow == [ "I am a fish" ]), overflow.text); +96 assert((results == SplitResults.overrun), Enum!SplitResults.toString(results)); +97 } +98 { +99 string line; +100 string abc, def; +101 string[] overflow; +102 immutable results = line.splitInto(abc, def, overflow); +103 assert((results == SplitResults.underrun), Enum!SplitResults.toString(results)); +104 } +105 { +106 string line = "abchonkelonkhonkelodef"; +107 string abc, def; +108 string[] overflow; +109 immutable results = line.splitInto!"honkelonk"(abc, def, overflow); +110 +111 assert((abc == "abc"), abc); +112 assert((def == "honkelodef"), def); +113 assert(!overflow.length, overflow.text); +114 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +115 } +116 { +117 string line = "honkelonkhonkelodef"; +118 string abc, def; +119 string[] overflow; +120 immutable results = line.splitInto!"honkelonk"(abc, def, overflow); +121 +122 assert((abc == "honkelodef"), abc); +123 assert((def == string.init), def); +124 assert(!overflow.length, overflow.text); +125 assert((results == SplitResults.underrun), Enum!SplitResults.toString(results)); +126 } +127 { +128 string line = "###########hirrsteff#snabel"; +129 string abc, def; +130 string[] overflow; +131 immutable results = line.splitInto!"#"(abc, def, overflow); +132 +133 assert((abc == "hirrsteff"), abc); +134 assert((def == "snabel"), def); +135 assert(!overflow.length, overflow.text); +136 assert((results == SplitResults.match), Enum!SplitResults.toString(results)); +137 } +138 { +139 string line = "abc def ghi"; +140 string[] overflow; +141 immutable results = line.splitInto(overflow); +142 immutable expectedOverflow = [ "abc", "def", "ghi" ]; +143 +144 assert((overflow == expectedOverflow), overflow.text); +145 assert((results == SplitResults.overrun), Enum!SplitResults.toString(results)); +146 }
Splits a string with on boundary as delimited by a supplied separator, into + one or more more lines not longer than the passed maximum length.
If a line cannot be split due to the line being too short or the separator + not occurring in the text, it is added to the returned array as-is and no + more splitting is done.
String line to split.
Separator character with which to split the line.
Maximum length of the separated lines.
A T[] array with lines split out of the passed line.
string line = "I am a fish in a sort of long sentence~"; +enum maxLineLength = 20; +auto splitLines = line.splitLineAtPosition(' ', maxLineLength); + +assert(splitLines[0] == "I am a fish in a"); +assert(splitLines[1] == "sort of a long"); +assert(splitLines[2] == "sentence~");
import std.conv : text; + +{ + immutable prelude = "PRIVMSG #garderoben :"; + immutable maxLength = 250 - prelude.length; + + immutable rawLine = "Lorem ipsum dolor sit amet, ea has velit noluisse, " ~ + "eos eius appetere constituto no, ad quas natum eos. Perpetua " ~ + "electram mnesarchum usu ne, mei vero dolorem no. Ea quando scripta " ~ + "quo, minim legendos ut vel. Ut usu graece equidem posidonium. Ius " ~ + "denique ponderum verterem no, quo te mentitum officiis referrentur. " ~ + "Sed an dolor iriure vocibus. " ~ + "Lorem ipsum dolor sit amet, ea has velit noluisse, " ~ + "eos eius appetere constituto no, ad quas natum eos. Perpetua " ~ + "electram mnesarchum usu ne, mei vero dolorem no. Ea quando scripta " ~ + "quo, minim legendos ut vel. Ut usu graece equidem posidonium. Ius " ~ + "denique ponderum verterem no, quo te mentitum officiis referrentur. " ~ + "Sed an dolor iriure vocibus. ssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssss"; + const splitLines = rawLine.splitLineAtPosition(' ', maxLength); + assert((splitLines.length == 4), splitLines.length.text); +} +{ + immutable prelude = "PRIVMSG #garderoben :"; + immutable maxLength = 250 - prelude.length; + + immutable rawLine = "ssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" ~ + "ssssssssssssssssssssssssssssssssssssssssssssssssssssssss"; + const splitLines = rawLine.splitLineAtPosition(' ', maxLength); + assert((splitLines.length == 1), splitLines.length.text); + assert(splitLines[0] == rawLine); +}
Splits a string into an array of strings by whitespace, but honours quotes.
Intended to be used with ASCII strings; may or may not work with more + elaborate UTF-8 strings.
A string[] composed of the input string split up into substrings, + delimited by whitespace. Quoted sections are treated as one substring.
string s = `title "this is my title" author "john doe"`; +immutable splitUp = splitWithQuotes(s); +assert(splitUp == [ "title", "this is my title", "author", "john doe" ]);
1 import std.conv : text; +2 +3 { +4 enum input = `title "this is my title" author "john doe"`; +5 immutable splitUp = splitWithQuotes(input); +6 immutable expected = +7 [ +8 "title", +9 "this is my title", +10 "author", +11 "john doe" +12 ]; +13 assert(splitUp == expected, splitUp.text); +14 } +15 { +16 enum input = `string without quotes`; +17 immutable splitUp = splitWithQuotes(input); +18 immutable expected = +19 [ +20 "string", +21 "without", +22 "quotes", +23 ]; +24 assert(splitUp == expected, splitUp.text); +25 } +26 { +27 enum input = string.init; +28 immutable splitUp = splitWithQuotes(input); +29 immutable expected = (string[]).init; +30 assert(splitUp == expected, splitUp.text); +31 } +32 { +33 enum input = `title "this is \"my\" title" author "john\\" doe`; +34 immutable splitUp = splitWithQuotes(input); +35 immutable expected = +36 [ +37 "title", +38 `this is "my" title`, +39 "author", +40 `john\`, +41 "doe" +42 ]; +43 assert(splitUp == expected, splitUp.text); +44 } +45 { +46 enum input = `title "this is \"my\" title" author "john\\\" doe`; +47 immutable splitUp = splitWithQuotes(input); +48 immutable expected = +49 [ +50 "title", +51 `this is "my" title`, +52 "author", +53 `john\" doe` +54 ]; +55 assert(splitUp == expected, splitUp.text); +56 } +57 { +58 enum input = `this has "unbalanced quotes`; +59 immutable splitUp = splitWithQuotes(input); +60 immutable expected = +61 [ +62 "this", +63 "has", +64 "unbalanced quotes" +65 ]; +66 assert(splitUp == expected, splitUp.text); +67 } +68 { +69 enum input = `""`; +70 immutable splitUp = splitWithQuotes(input); +71 immutable expected = (string[]).init; +72 assert(splitUp == expected, splitUp.text); +73 } +74 { +75 enum input = `"`; +76 immutable splitUp = splitWithQuotes(input); +77 immutable expected = (string[]).init; +78 assert(splitUp == expected, splitUp.text); +79 } +80 { +81 enum input = `"""""""""""`; +82 immutable splitUp = splitWithQuotes(input); +83 immutable expected = (string[]).init; +84 assert(splitUp == expected, splitUp.text); +85 }
Strips the supplied string from the end of a string.
line with suffix sliced off the end.
string suffixed = "Kameloso"; +string stripped = suffixed.stripSuffix("oso"); +assert((stripped == "Kamel"), stripped);
immutable line = "harblsnarbl"; +assert(line.stripSuffix("snarbl") == "harbl"); +assert(line.stripSuffix("") == "harblsnarbl"); +assert(line.stripSuffix("INVALID") == "harblsnarbl"); +assert(!line.stripSuffix("harblsnarbl").length);
Returns a slice of the passed string with any preceding or trailing + whitespace or linebreaks sliced off both ends. Overload that implicitly + strips " \n\r\t".
It merely calls both strippedLeft and strippedRight. As such it + duplicates std.string.strip, which we can no longer trust not to assert + on unexpected input.
Line to strip both the right and left side of.
The passed line, stripped of surrounding whitespace.
static if (!is(typeof("blah".stripped) == string)) +{ + enum message = "`lu.string.stripped` should return a mutable string"; + static assert(0, message); +} + +{ + immutable line = " abc "; + immutable stripped_ = line.stripped; + assert((stripped_ == "abc"), stripped_); +} +{ + immutable line = " "; + immutable stripped_ = line.stripped; + assert((stripped_ == ""), stripped_); +} +{ + immutable line = ""; + immutable stripped_ = line.stripped; + assert((stripped_ == ""), stripped_); +} +{ + immutable line = "abc"; + immutable stripped_ = line.stripped; + assert((stripped_ == "abc"), stripped_); +} +{ + immutable line = " \r\n abc\r\n\r\n"; + immutable stripped_ = line.stripped; + assert((stripped_ == "abc"), stripped_); +}
Returns a slice of the passed string with any preceding or trailing + passed characters sliced off. Implementation template capable of handling both + individual characters and strings of tokens to strip.
It merely calls both strippedLeft and strippedRight. As such it + duplicates std.string.strip, which we can no longer trust not to assert + on unexpected input.
Line to strip both the right and left side of.
Character or string of characters to strip away.
The passed line, stripped of surrounding passed characters.
{ + immutable line = " abc "; + immutable stripped_ = line.stripped(' '); + assert((stripped_ == "abc"), stripped_); +} +{ + immutable line = "!!!"; + immutable stripped_ = line.stripped('!'); + assert((stripped_ == ""), stripped_); +} +{ + immutable line = ""; + immutable stripped_ = line.stripped('_'); + assert((stripped_ == ""), stripped_); +} +{ + immutable line = "abc"; + immutable stripped_ = line.stripped('\t'); + assert((stripped_ == "abc"), stripped_); +} +{ + immutable line = " \r\n abc\r\n\r\n "; + immutable stripped_ = line.stripped(' '); + assert((stripped_ == "\r\n abc\r\n\r\n"), stripped_); +} +{ + immutable line = " abc "; + immutable stripped_ = line.stripped(" \t"); + assert((stripped_ == "abc"), stripped_); +} +{ + immutable line = "!,!!"; + immutable stripped_ = line.stripped("!,"); + assert((stripped_ == ""), stripped_); +} +{ + immutable line = ""; + immutable stripped_ = line.stripped("_"); + assert((stripped_ == ""), stripped_); +} +{ + immutable line = "abc"; + immutable stripped_ = line.stripped("\t\r\n"); + assert((stripped_ == "abc"), stripped_); +} +{ + immutable line = " \r\n abc\r\n\r\n "; + immutable stripped_ = line.stripped(" _"); + assert((stripped_ == "\r\n abc\r\n\r\n"), stripped_); +}
Returns a slice of the passed string with any preceding whitespace and/or + linebreaks sliced off. Overload that implicitly strips " \n\r\t".
Duplicates std.string.stripLeft, which we can no longer trust not to + assert on unexpected input.
Line to strip the left side of.
The passed line without any preceding whitespace or linebreaks.
static if (!is(typeof("blah".strippedLeft) == string)) +{ + enum message = "`lu.string.strippedLeft` should return a mutable string"; + static assert(0, message); +} + +{ + immutable preceded = " abc"; + immutable stripped = preceded.strippedLeft; + assert((stripped == "abc"), stripped); +} +{ + immutable preceded = " "; + immutable stripped = preceded.strippedLeft; + assert((stripped == ""), stripped); +} +{ + immutable empty = ""; + immutable stripped = empty.strippedLeft; + assert((stripped == ""), stripped); +} +{ + immutable noPreceded = "abc"; + immutable stripped = noPreceded.strippedLeft; + assert((stripped == noPreceded), stripped); +} +{ + immutable linebreak = "\r\n\r\n abc"; + immutable stripped = linebreak.strippedLeft; + assert((stripped == "abc"), stripped); +}
Returns a slice of the passed string with any preceding passed characters + sliced off. Implementation capable of handling both individual characters + and strings of tokens to strip.
Duplicates std.string.stripLeft, which we can no longer trust not to + assert on unexpected input.
The passed line without any preceding passed characters.
{ + immutable trailing = ",abc"; + immutable stripped = trailing.strippedLeft(','); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "!!!abc"; + immutable stripped = trailing.strippedLeft('!'); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "abc"; + immutable stripped = trailing.strippedLeft(' '); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = ""; + immutable stripped = trailing.strippedLeft(' '); + assert(!stripped.length, stripped); +} +{ + immutable trailing = ",abc"; + immutable stripped = trailing.strippedLeft(","); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "!!!abc"; + immutable stripped = trailing.strippedLeft(",1!"); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "abc"; + immutable stripped = trailing.strippedLeft(" "); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = ""; + immutable stripped = trailing.strippedLeft(" "); + assert(!stripped.length, stripped); +}
Returns a slice of the passed string with any trailing whitespace and/or + linebreaks sliced off. Overload that implicitly strips " \n\r\t".
Duplicates std.string.stripRight, which we can no longer trust not to + assert on unexpected input.
Line to strip the right side of.
The passed line without any trailing whitespace or linebreaks.
static if (!is(typeof("blah".strippedRight) == string)) +{ + enum message = "`lu.string.strippedRight` should return a mutable string"; + static assert(0, message); +} + +{ + immutable trailing = "abc "; + immutable stripped = trailing.strippedRight; + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = " "; + immutable stripped = trailing.strippedRight; + assert((stripped == ""), stripped); +} +{ + immutable empty = ""; + immutable stripped = empty.strippedRight; + assert((stripped == ""), stripped); +} +{ + immutable noTrailing = "abc"; + immutable stripped = noTrailing.strippedRight; + assert((stripped == "abc"), stripped); +} +{ + immutable linebreak = "abc\r\n \r\n"; + immutable stripped = linebreak.strippedRight; + assert((stripped == "abc"), stripped); +}
Returns a slice of the passed string with any trailing passed characters. + Implementation template capable of handling both individual characters and + string of tokens to strip.
Duplicates std.string.stripRight, which we can no longer trust not to + assert on unexpected input.
Line to strip the right side of.
Character or string of characters to strip away.
The passed line without any trailing passed characters.
{ + immutable trailing = "abc,"; + immutable stripped = trailing.strippedRight(','); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "abc!!!"; + immutable stripped = trailing.strippedRight('!'); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "abc"; + immutable stripped = trailing.strippedRight(' '); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = ""; + immutable stripped = trailing.strippedRight(' '); + assert(!stripped.length, stripped); +} +{ + immutable trailing = "abc,!.-"; + immutable stripped = trailing.strippedRight("-.!,"); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "abc!!!"; + immutable stripped = trailing.strippedRight("!"); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = "abc"; + immutable stripped = trailing.strippedRight(" ABC"); + assert((stripped == "abc"), stripped); +} +{ + immutable trailing = ""; + immutable stripped = trailing.strippedRight(" "); + assert(!stripped.length, stripped); +}
Returns a range of *spaces* equal to that of num tabs (\t).
Use std.conv.to or std.conv.text or similar to flatten to a string.
A range of whitespace equalling (num * spaces) spaces.
string indentation = 2.tabs.text; +assert((indentation == " "), `"` ~ indentation ~ `"`); +string smallIndent = 1.tabs!2.text; +assert((smallIndent == " "), `"` ~ smallIndent ~ `"`);
import std.array : Appender; +import std.conv : to; +import std.exception : assertThrown; +import std.format : formattedWrite; +import std.algorithm.comparison : equal; +import core.exception : AssertError; + +auto one = 1.tabs!4; +auto two = 2.tabs!3; +auto three = 3.tabs!2; +auto zero = 0.tabs; + +assert(one.equal(" "), one.to!string); +assert(two.equal(" "), two.to!string); +assert(three.equal(" "), three.to!string); +assert(zero.equal(string.init), zero.to!string); + +assertThrown!AssertError((-1).tabs); + +Appender!(char[]) sink; +sink.formattedWrite("%sHello world", 2.tabs!2); +assert((sink.data == " Hello world"), sink.data);
Removes paired preceding and trailing tokens around a string line. + Assumes ASCII.
You should not need to use this directly; rather see unquoted and + unsinglequoted.
Removes paired preceding and trailing double quotes, unquoting a word. + Assumes ASCII.
Does not decode the string and may thus give weird results on weird inputs.
The (potentially) quoted string.
A slice of the line argument that excludes the quotes.
string quoted = `"This is a quote"`; +string unquotedLine = quoted.unquoted; +assert((unquotedLine == "This is a quote"), unquotedLine);
assert(`"Lorem ipsum sit amet"`.unquoted == "Lorem ipsum sit amet"); +assert(`"""""Lorem ipsum sit amet"""""`.unquoted == "Lorem ipsum sit amet"); +// Unbalanced quotes are left untouched +assert(`"Lorem ipsum sit amet`.unquoted == `"Lorem ipsum sit amet`); +assert(`"Lorem \"`.unquoted == `"Lorem \"`); +assert("\"Lorem \\\"".unquoted == "\"Lorem \\\""); +assert(`"\"`.unquoted == `"\"`);
Removes paired preceding and trailing single quotes around a line. + Assumes ASCII.
Does not decode the string and may thus give weird results on weird inputs.
The (potentially) single-quoted string.
A slice of the line argument that excludes the single-quotes.
string quoted = `'This is single-quoted'`; +string unquotedLine = quoted.unsinglequoted; +assert((unquotedLine == "This is single-quoted"), unquotedLine);
assert(`'Lorem ipsum sit amet'`.unsinglequoted == "Lorem ipsum sit amet"); +assert(`''''Lorem ipsum sit amet''''`.unsinglequoted == "Lorem ipsum sit amet"); +// Unbalanced quotes are left untouched +assert(`'Lorem ipsum sit amet`.unsinglequoted == `'Lorem ipsum sit amet`); +assert(`'Lorem \'`.unsinglequoted == `'Lorem \'`); +assert("'Lorem \\'".unsinglequoted == "'Lorem \\'"); +assert(`'`.unsinglequoted == `'`);
The fully qualified name for the symbol sym is an alias of.
Provides string representations of the category of a symbol, where such is not + a fundamental primitive variable but a module, a function, a delegate, + a class or a struct.
Accurate module detection only works on compilers 2.087 and later, due to + missing support for __traits(isModule).
The fully qualified name for the symbol sym is an alias of.
A short name for the symbol sym is an alias of.
Symbol to provide the strings for.
module foo; + +void bar() {} + +alias categoryName = CategoryName!bar; + +assert(categoryName.type == "function"); +assert(categoryName.name == "bar"); +assert(categoryName.fqn == "foo.bar");
bool localSymbol; + +void fn() {} + +auto dg = () => localSymbol; + +class C {} +C c; + +struct S {} +S s; + +interface I {} + +union U +{ + int i; + bool b; +} + +U u; + +alias Ffn = CategoryName!fn; +static assert(Ffn.type == "function"); +static assert(Ffn.name == "fn"); +// Can't test fqn from inside a unittest + +alias Fdg = CategoryName!dg; +static assert(Fdg.type == "delegate"); +static assert(Fdg.name == "dg"); +// Ditto + +alias Fc = CategoryName!c; +static assert(Fc.type == "class"); +static assert(Fc.name == "c"); +// Ditto + +alias Fs = CategoryName!s; +static assert(Fs.type == "struct"); +static assert(Fs.name == "s"); + +alias Fm = CategoryName!(lu.traits); +static assert(Fm.type == "module"); +static assert(Fm.name == "traits"); +static assert(Fm.fqn == "lu.traits"); + +alias Fi = CategoryName!I; +static assert(Fi.type == "interface"); +static assert(Fi.name == "I"); + +alias Fu = CategoryName!u; +static assert(Fu.type == "union"); +static assert(Fu.name == "u");
A short name for the symbol sym is an alias of.
Mixes in constraints into another mixin template, to provide static + guarantees that it is not mixed into a type of scope other than the one specified.
Using this you can ensure that a mixin template meant to be mixed into a + class isn't mixed into a module-level scope, or into a function, etc.
More than one scope type can be supplied with bitwise OR.
The scope into which to only allow the mixin to be mixed in. + All other kinds of scopes will be statically rejected.
Optional string name of the mixing-in mixin. + Can be anything; it's just used for the error messages.
module foo; + +mixin template Foo() +{ + mixin MixinConstraints!(MixinScope.module_, "Foo"); // Constrained to module-level scope +} + +mixin Foo; // no problem, scope is MixinScope.module_ + +void bar() +{ + mixin Foo; // static assert(0): scope is MixinScope.function_, not MixinScope.module_ +} + +class C +{ + mixin Foo; // static assert(0): ditto but MixinScope.class_ +} + +struct C +{ + mixin Foo; // static assert(0): ditto but MixinScope.struct_ +} + +mixin template FooStructOrClass() +{ + mixin MixinConstraints(MixinScope.struct_ | MixinScope.class_); +}
void fun() +{ + // MixinConstraints!(MixinScope.function_, "TestMixinConstrainedToFunctions"); + mixin TestMixinConstrainedToFunctions; +} + +class TestClassC +{ + // MixinConstraints!(MixinScope.class_, "TestMixinConstrainedToClass"); + mixin TestMixinConstrainedToClass; +} + +struct TestStructS +{ + // mixin MixinConstraints!(MixinScope.struct_, "TestMixinConstrainedToStruct"); + mixin TestMixinConstrainedToStruct; +} + +struct TestStructS2 +{ + mixin TestMixinConstrainedToClassOrStruct; +}
The types of scope into which a mixin template may be mixed in.
Value | Meaning |
---|---|
function_1 << 0 | Mixed in inside a function. |
class_1 << 1 | Mixed in inside a class. |
struct_1 << 2 | Mixed in inside a struct. |
interface_1 << 3 | Mixed in inside an interface. |
union_1 << 4 | Mixed in inside a union. |
module_1 << 5 | Mixed in inside a module. |
Given a function and a tuple of types, evaluates whether that function could + be called with that tuple as parameters. Alias version (works on functions, + not function types.)
Qualifiers like const andimmutable are skipped, which may make it a poor + choice if dealing with functions that require such arguments.
It is merely syntactic sugar, using std.meta and std.traits behind the scenes.
Function to evaluate the parameters of.
Variadic list of types to compare fun's function parameters with.
void noParams(); +bool boolParam(bool); +string stringParam(string); +float floatParam(float); + +static assert(TakesParams!(noParams)); +static assert(TakesParams!(boolParam, bool)); +static assert(TakesParams!(stringParam, string)); +static assert(TakesParams!(floatParam, float));
void foo(); +void foo1(string); +void foo2(string, int); +void foo3(bool, bool, bool); + +static assert(TakesParams!(foo));//, AliasSeq!())); +static assert(TakesParams!(foo1, string)); +static assert(TakesParams!(foo2, string, int)); +static assert(TakesParams!(foo3, bool, bool, bool)); + +static assert(!TakesParams!(foo, string)); +static assert(!TakesParams!(foo1, string, int)); +static assert(!TakesParams!(foo2, bool, bool, bool));
Given a function and a tuple of types, evaluates whether that function could + be called with that tuple as parameters. Non-alias version (works on types).
Qualifiers like const and immutable are skipped, which may make it a + poor choice if dealing with functions that require such arguments.
It is merely syntactic sugar, using std.meta and std.traits behind the scenes.
Type of function to evaluate the parameters of.
Variadic list of types to compare Fun function parameters with.
void noParams(); +bool boolParam(bool); +string stringParam(string); +float floatParam(float); + +alias N = typeof(noParams); +alias B = typeof(boolParam); +alias S = typeof(stringParam); +alias F = typeof(floatParam); + +static assert(TakesParams!N); +static assert(TakesParams!(B, bool)); +static assert(TakesParams!(S, string)); +static assert(TakesParams!(F, float));
void foo(); +void foo1(string); +void foo2(string, int); +void foo3(bool, bool, bool); + +alias F = typeof(foo); +alias F1 = typeof(foo1); +alias F2 = typeof(foo2); +alias F3 = typeof(foo3); + +static assert(TakesParams!F);//, AliasSeq!())); +static assert(TakesParams!(F1, string)); +static assert(TakesParams!(F2, string, int)); +static assert(TakesParams!(F3, bool, bool, bool)); + +static assert(!TakesParams!(F, string)); +static assert(!TakesParams!(F1, string, int)); +static assert(!TakesParams!(F2, bool, bool, bool));
Given an array of qualified elements, aliases itself to one such of + unqualified elements.
alias ConstStrings = const(string)[]; +alias UnqualStrings = UnqualArray!ConstStrings; +static assert(is(UnqualStrings == string[])); + +alias ImmChars = string; +alias UnqualChars = UnqualArray!ImmChars; +static assert(is(UnqualChars == char[])); + +alias InoutBools = inout(bool)[]; +alias UnqualBools = UnqualArray!InoutBools; +static assert(is(UnqualBools == bool[])); + +alias ConstChars = const(char)[]; +alias UnqualChars2 = UnqualArray!ConstChars; +static assert(is(UnqualChars2 == char[]));
Given an associative array with elements that have a storage class, aliases + itself to an associative array with elements without the storage classes.
Qualified associative array type.
Qualified type, element of QualArray.
Qualified type, key of QualArray.
alias ConstStringAA = const(string)[int]; +alias UnqualStringAA = UnqualArray!ConstStringAA; +static assert (is(UnqualStringAA == string[int])); + +alias ImmIntAA = immutable(int)[char]; +alias UnqualIntAA = UnqualArray!ImmIntAA; +static assert(is(UnqualIntAA == int[char])); + +alias InoutBoolAA = inout(bool)[long]; +alias UnqualBoolAA = UnqualArray!InoutBoolAA; +static assert(is(UnqualBoolAA == bool[long])); + +alias ConstCharAA = const(char)[string]; +alias UnqualCharAA = UnqualArray!ConstCharAA; +static assert(is(UnqualCharAA == char[string]));
Given an associative array of arrays with a storage class, aliases itself to + an associative array with array elements without the storage classes.
Qualified associative array type.
Qualified type, element of QualArray.
Qualified type, key of QualArray.
alias ConstStringArrays = const(string[])[int]; +alias UnqualStringArrays = UnqualArray!ConstStringArrays; +static assert (is(UnqualStringArrays == string[][int])); + +alias ImmIntArrays = immutable(int[])[char]; +alias UnqualIntArrays = UnqualArray!ImmIntArrays; +static assert(is(UnqualIntArrays == int[][char])); + +alias InoutBoolArrays = inout(bool)[][long]; +alias UnqualBoolArrays = UnqualArray!InoutBoolArrays; +static assert(is(UnqualBoolArrays == bool[][long])); + +alias ConstCharArrays = const(char)[][string]; +alias UnqualCharArrays = UnqualArray!ConstCharArrays; +static assert(is(UnqualCharArrays == char[][string]));
Provide a non-2.088, non-2.089 getSymbolsByUDA.
The getSymbolsByUDA in 2.088/2.089 is + completely broken by having inserted a constraint to force it to only + work on aggregates, which a module apparently isn't.
Implementation of getSymbolsByUDA, copy/pasted.
Various compile-time traits and cleverness.
The types of scope into which a mixin template may be mixed in.
True if a type is a non-string array; otherwise false.
Evaluates whether or not a passed array type is a mutable array of immutable + elements, such as a string.
Eponymous template that is true if the passed type is a struct.
True if a type is string, dstring or wstring; otherwise false.
Mixes in constraints into another mixin template, to provide static + guarantees that it is not mixed into a type of scope other than the one specified.
Provides string representations of the category of a symbol, where such is not + a fundamental primitive variable but a module, a function, a delegate, + a class or a struct.
Given a function and a tuple of types, evaluates whether that function could + be called with that tuple as parameters. Alias version (works on functions, + not function types.)
Given a function and a tuple of types, evaluates whether that function could + be called with that tuple as parameters. Non-alias version (works on types).
Given an array of qualified elements, aliases itself to one such of + unqualified elements.
Given an associative array with elements that have a storage class, aliases + itself to an associative array with elements without the storage classes.
Given an associative array of arrays with a storage class, aliases itself to + an associative array with array elements without the storage classes.
Provide a non-2.088, non-2.089 getSymbolsByUDA.
Implementation of getSymbolsByUDA, copy/pasted.
Eponymous template bool of whether a variable can be treated as a mutable + variable, like a fundamental integral, and thus be serialised.
Produces a string of the unqualified parameters of the passed function alias.
True if a type is a non-string array; otherwise false.
For now also evaluates to true for static arrays.
Array type to introspect.
static assert(!isMerelyArray!string); +static assert(!isMerelyArray!dstring); +static assert(!isMerelyArray!wstring); +static assert(isMerelyArray!(char[])); +static assert(isMerelyArray!(dchar[])); +static assert(isMerelyArray!(wchar[])); +static assert(isMerelyArray!(int[5]));
Evaluates whether or not a passed array type is a mutable array of immutable + elements, such as a string.
Array to inspect.
static assert(isMutableArrayOfImmutables!string); +static assert(isMutableArrayOfImmutables!wstring); +static assert(isMutableArrayOfImmutables!dstring); +static assert(!isMutableArrayOfImmutables!(immutable(string))); + +static assert(isMutableArrayOfImmutables!(immutable(int)[])); +static assert(!isMutableArrayOfImmutables!(immutable(int[])));
Eponymous template bool of whether a variable can be treated as a mutable + variable, like a fundamental integral, and thus be serialised.
Currently it does not support static arrays.
Alias of symbol to introspect.
int i; +char[] c; +char[8] c2; +struct S {} +class C {} +enum E { foo } +E e; + +static assert(isSerialisable!i); +static assert(isSerialisable!c); +static assert(!isSerialisable!c2); // should static arrays pass? +static assert(!isSerialisable!S); +static assert(!isSerialisable!C); +static assert(!isSerialisable!E); +static assert(isSerialisable!e);
Eponymous template that is true if the passed type is a struct.
Used with std.meta.Filter, which cannot take is() expressions.
Type to introspect.
True if a type is string, dstring or wstring; otherwise false.
Does not consider e.g. char[] a string, as + isSomeString does.
String type to introspect.
static assert(isTrulyString!string); +static assert(isTrulyString!dstring); +static assert(isTrulyString!wstring); +static assert(!isTrulyString!(char[])); +static assert(!isTrulyString!(dchar[])); +static assert(!isTrulyString!(wchar[]));
Produces a string of the unqualified parameters of the passed function alias.
A function alias to get the parameter string of.
void foo(bool b, int i, string s) {} +static assert(stringofParams!foo == "bool, int, string");
void foo(); +void foo1(string); +void foo2(string, int); +void foo3(bool, bool, bool); + +enum ofFoo = stringofParams!foo; +enum ofFoo1 = stringofParams!foo1; +enum ofFoo2 = stringofParams!foo2; +enum ofFoo3 = stringofParams!foo3; + +static assert(!ofFoo.length, ofFoo); +static assert((ofFoo1 == "string"), ofFoo1); +static assert((ofFoo2 == "string, int"), ofFoo2); +static assert((ofFoo3 == "bool, bool, bool"), ofFoo3);
Mixin template generating an opDispatch redirecting calls to members whose + names match the passed variable string but with an underscore prepended.
Mutator.
Accessor.
{ + struct Foo + { + int _i; + string _s; + bool _b; + string[] _add; + alias wordList = _add; + + mixin UnderscoreOpDispatcher; + } + + Foo f; + f.i = 42; // f.opDispatch!"i"(42); + f.s = "hello"; // f.opDispatch!"s"("hello"); + f.b = true; // f.opDispatch!"b"(true); + f.add("hello"); // f.opDispatch!"add"("hello"); + f.add("world"); // f.opDispatch!"add"("world"); + + assert(f.i == 42); + assert(f.s == "hello"); + assert(f.b); + assert(f.wordList == [ "hello", "world" ]); + + /+ + Returns `this` by reference, so we can chain calls. + +/ + auto f2 = Foo() + .i(9001) + .s("world") + .b(false) + .add("hello") + .add("world"); + + assert(f2.i == 9001); + assert(f2.s == "world"); + assert(!f2.b); + assert(f2.wordList == [ "hello", "world" ]); +} +{ + struct Bar + { + string[string] _aa; + + mixin UnderscoreOpDispatcher; + } + + Bar bar; + bar.aa = [ "hello" : "world" ]; + bar.aa = [ "foo" : "bar" ]; + assert(bar.aa == [ "hello" : "world", "foo" : "bar"]); +}
Mutator.
Accessor.
Type constructors.
Mixin template generating an opDispatch redirecting calls to members whose + names match the passed variable string but with an underscore prepended.
UDA conveying that this member may contain characters that would otherwise + indicate a comment, but isn't.
UDA conveying that this member contains sensitive information and should not + be printed in clear text; e.g. passwords.
UDA conveying that this member's value must be quoted when serialised.
Separator, can be more than one character.
UDA conveying that a field cannot (or should not) be serialised.
Common user-defined attributes (UDAs).
UDA conveying that this member may contain characters that would otherwise + indicate a comment, but isn't.
UDA conveying that this member contains sensitive information and should not + be printed in clear text; e.g. passwords.
UDA conveying that this member's value must be quoted when serialised.
UDA conveying that a field cannot (or should not) be serialised.
UDA conveying that the annotated array should have this token as separator + when formatted to a string.