This repository has been archived by the owner on Jul 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move number functions to own compile unit
- Loading branch information
Showing
7 changed files
with
271 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
#include <cstdint> | ||
#include <cstdlib> | ||
#include <cmath> | ||
#include <cctype> | ||
#include <random> | ||
#include <sstream> | ||
#include <iomanip> | ||
#include <algorithm> | ||
|
||
#include "ast.hpp" | ||
#include "sass.hpp" | ||
#include "units.hpp" | ||
#include "fn_utils.hpp" | ||
#include "fn_numbers.hpp" | ||
|
||
#ifdef __MINGW32__ | ||
#include "windows.h" | ||
#include "wincrypt.h" | ||
#endif | ||
|
||
namespace Sass { | ||
|
||
namespace Functions { | ||
|
||
#ifdef __MINGW32__ | ||
uint64_t GetSeed() | ||
{ | ||
HCRYPTPROV hp = 0; | ||
BYTE rb[8]; | ||
CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); | ||
CryptGenRandom(hp, sizeof(rb), rb); | ||
CryptReleaseContext(hp, 0); | ||
|
||
uint64_t seed; | ||
memcpy(&seed, &rb[0], sizeof(seed)); | ||
|
||
return seed; | ||
} | ||
#else | ||
uint64_t GetSeed() | ||
{ | ||
std::random_device rd; | ||
return rd(); | ||
} | ||
#endif | ||
|
||
// note: the performance of many implementations of | ||
// random_device degrades sharply once the entropy pool | ||
// is exhausted. For practical use, random_device is | ||
// generally only used to seed a PRNG such as mt19937. | ||
static std::mt19937 rand(static_cast<unsigned int>(GetSeed())); | ||
|
||
/////////////////// | ||
// NUMBER FUNCTIONS | ||
/////////////////// | ||
|
||
Signature percentage_sig = "percentage($number)"; | ||
BUILT_IN(percentage) | ||
{ | ||
Number_Obj n = ARGN("$number"); | ||
if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate, traces); | ||
return SASS_MEMORY_NEW(Number, pstate, n->value() * 100, "%"); | ||
} | ||
|
||
Signature round_sig = "round($number)"; | ||
BUILT_IN(round) | ||
{ | ||
Number_Obj r = ARGN("$number"); | ||
r->value(Sass::round(r->value(), ctx.c_options.precision)); | ||
r->pstate(pstate); | ||
return r.detach(); | ||
} | ||
|
||
Signature ceil_sig = "ceil($number)"; | ||
BUILT_IN(ceil) | ||
{ | ||
Number_Obj r = ARGN("$number"); | ||
r->value(std::ceil(r->value())); | ||
r->pstate(pstate); | ||
return r.detach(); | ||
} | ||
|
||
Signature floor_sig = "floor($number)"; | ||
BUILT_IN(floor) | ||
{ | ||
Number_Obj r = ARGN("$number"); | ||
r->value(std::floor(r->value())); | ||
r->pstate(pstate); | ||
return r.detach(); | ||
} | ||
|
||
Signature abs_sig = "abs($number)"; | ||
BUILT_IN(abs) | ||
{ | ||
Number_Obj r = ARGN("$number"); | ||
r->value(std::abs(r->value())); | ||
r->pstate(pstate); | ||
return r.detach(); | ||
} | ||
|
||
Signature min_sig = "min($numbers...)"; | ||
BUILT_IN(min) | ||
{ | ||
List_Ptr arglist = ARG("$numbers", List); | ||
Number_Obj least = NULL; | ||
for (size_t i = 0, L = arglist->length(); i < L; ++i) { | ||
Expression_Obj val = arglist->value_at_index(i); | ||
Number_Obj xi = Cast<Number>(val); | ||
if (!xi) { | ||
error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate, traces); | ||
} | ||
if (least) { | ||
if (*xi < *least) least = xi; | ||
} else least = xi; | ||
} | ||
return least.detach(); | ||
} | ||
|
||
Signature max_sig = "max($numbers...)"; | ||
BUILT_IN(max) | ||
{ | ||
List_Ptr arglist = ARG("$numbers", List); | ||
Number_Obj greatest = NULL; | ||
for (size_t i = 0, L = arglist->length(); i < L; ++i) { | ||
Expression_Obj val = arglist->value_at_index(i); | ||
Number_Obj xi = Cast<Number>(val); | ||
if (!xi) { | ||
error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate, traces); | ||
} | ||
if (greatest) { | ||
if (*greatest < *xi) greatest = xi; | ||
} else greatest = xi; | ||
} | ||
return greatest.detach(); | ||
} | ||
|
||
Signature random_sig = "random($limit:false)"; | ||
BUILT_IN(random) | ||
{ | ||
AST_Node_Obj arg = env["$limit"]; | ||
Value_Ptr v = Cast<Value>(arg); | ||
Number_Ptr l = Cast<Number>(arg); | ||
Boolean_Ptr b = Cast<Boolean>(arg); | ||
if (l) { | ||
double lv = l->value(); | ||
if (lv < 1) { | ||
std::stringstream err; | ||
err << "$limit " << lv << " must be greater than or equal to 1 for `random'"; | ||
error(err.str(), pstate, traces); | ||
} | ||
bool eq_int = std::fabs(trunc(lv) - lv) < NUMBER_EPSILON; | ||
if (!eq_int) { | ||
std::stringstream err; | ||
err << "Expected $limit to be an integer but got " << lv << " for `random'"; | ||
error(err.str(), pstate, traces); | ||
} | ||
std::uniform_real_distribution<> distributor(1, lv + 1); | ||
uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand)); | ||
return SASS_MEMORY_NEW(Number, pstate, (double)distributed); | ||
} | ||
else if (b) { | ||
std::uniform_real_distribution<> distributor(0, 1); | ||
double distributed = static_cast<double>(distributor(rand)); | ||
return SASS_MEMORY_NEW(Number, pstate, distributed); | ||
} else if (v) { | ||
traces.push_back(Backtrace(pstate)); | ||
throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number", v); | ||
} else { | ||
traces.push_back(Backtrace(pstate)); | ||
throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number"); | ||
} | ||
} | ||
|
||
Signature unique_id_sig = "unique-id()"; | ||
BUILT_IN(unique_id) | ||
{ | ||
std::stringstream ss; | ||
std::uniform_real_distribution<> distributor(0, 4294967296); // 16^8 | ||
uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand)); | ||
ss << "u" << std::setfill('0') << std::setw(8) << std::hex << distributed; | ||
return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str()); | ||
} | ||
|
||
Signature unit_sig = "unit($number)"; | ||
BUILT_IN(unit) | ||
{ | ||
Number_Obj arg = ARGN("$number"); | ||
std::string str(quote(arg->unit(), '"')); | ||
return SASS_MEMORY_NEW(String_Quoted, pstate, str); | ||
} | ||
|
||
Signature unitless_sig = "unitless($number)"; | ||
BUILT_IN(unitless) | ||
{ | ||
Number_Obj arg = ARGN("$number"); | ||
bool unitless = arg->is_unitless(); | ||
return SASS_MEMORY_NEW(Boolean, pstate, unitless); | ||
} | ||
|
||
Signature comparable_sig = "comparable($number-1, $number-2)"; | ||
BUILT_IN(comparable) | ||
{ | ||
Number_Obj n1 = ARGN("$number-1"); | ||
Number_Obj n2 = ARGN("$number-2"); | ||
if (n1->is_unitless() || n2->is_unitless()) { | ||
return SASS_MEMORY_NEW(Boolean, pstate, true); | ||
} | ||
// normalize into main units | ||
n1->normalize(); n2->normalize(); | ||
Units &lhs_unit = *n1, &rhs_unit = *n2; | ||
bool is_comparable = (lhs_unit == rhs_unit); | ||
return SASS_MEMORY_NEW(Boolean, pstate, is_comparable); | ||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#ifndef SASS_FN_NUMBERS_H | ||
#define SASS_FN_NUMBERS_H | ||
|
||
#include "fn_utils.hpp" | ||
|
||
namespace Sass { | ||
|
||
namespace Functions { | ||
|
||
// return a number object (copied since we want to have reduced units) | ||
#define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy | ||
|
||
extern Signature percentage_sig; | ||
extern Signature round_sig; | ||
extern Signature ceil_sig; | ||
extern Signature floor_sig; | ||
extern Signature abs_sig; | ||
extern Signature min_sig; | ||
extern Signature max_sig; | ||
extern Signature inspect_sig; | ||
extern Signature random_sig; | ||
extern Signature unique_id_sig; | ||
extern Signature unit_sig; | ||
extern Signature unitless_sig; | ||
extern Signature comparable_sig; | ||
|
||
BUILT_IN(percentage); | ||
BUILT_IN(round); | ||
BUILT_IN(ceil); | ||
BUILT_IN(floor); | ||
BUILT_IN(abs); | ||
BUILT_IN(min); | ||
BUILT_IN(max); | ||
BUILT_IN(inspect); | ||
BUILT_IN(random); | ||
BUILT_IN(unique_id); | ||
BUILT_IN(unit); | ||
BUILT_IN(unitless); | ||
BUILT_IN(comparable); | ||
|
||
} | ||
|
||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters