diff --git a/examples/custom_schema.cpp b/examples/custom_schema.cpp index c35eadb..3b15138 100644 --- a/examples/custom_schema.cpp +++ b/examples/custom_schema.cpp @@ -159,14 +159,14 @@ void addRequiredConstraint(Schema &schema) requiredProperties.insert("category"); requiredProperties.insert("price"); requiredProperties.insert("title"); - schema.addConstraint(new RequiredConstraint(requiredProperties)); + schema.addConstraint(RequiredConstraint(requiredProperties)); } void addTypeConstraint(Schema &schema) { // Add a TypeConstraint to the schema, specifying that the root of the // document must be an object. - schema.addConstraint(new TypeConstraint(TypeConstraint::kObject)); + schema.addConstraint(TypeConstraint(TypeConstraint::kObject)); } int main(int argc, char *argv[]) diff --git a/include/valijson/constraints/basic_constraint.hpp b/include/valijson/constraints/basic_constraint.hpp index af1682b..eccf05b 100644 --- a/include/valijson/constraints/basic_constraint.hpp +++ b/include/valijson/constraints/basic_constraint.hpp @@ -25,9 +25,21 @@ struct BasicConstraint: Constraint return visitor.visit(*static_cast(this)); } - virtual Constraint * clone() const + virtual Constraint * clone(CustomAlloc allocFn, CustomFree freeFn) const { - return new ConstraintType(*static_cast(this)); + void *ptr = allocFn(sizeof(ConstraintType)); + if (!ptr) { + throw std::runtime_error( + "Failed to allocate memory for cloned constraint"); + } + + try { + return new (ptr) ConstraintType( + *static_cast(this)); + } catch (...) { + freeFn(ptr); + throw; + } } }; diff --git a/include/valijson/constraints/constraint.hpp b/include/valijson/constraints/constraint.hpp index c4709dc..c053dbb 100644 --- a/include/valijson/constraints/constraint.hpp +++ b/include/valijson/constraints/constraint.hpp @@ -12,7 +12,13 @@ class ConstraintVisitor; * * @todo Consider using something like the boost::cloneable concept here. */ -struct Constraint { +struct Constraint +{ + /// Typedef for custom new-/malloc-like function + typedef void * (*CustomAlloc)(size_t size); + + /// Typedef for custom free-like function + typedef void (*CustomFree)(void *); /** * @brief Virtual destructor. @@ -38,15 +44,10 @@ struct Constraint { * * @returns an owning-pointer to the new constraint. */ - virtual Constraint * clone() const = 0; + virtual Constraint * clone(CustomAlloc, CustomFree) const = 0; }; -inline Constraint * new_clone(const Constraint &constraint) -{ - return constraint.clone(); -} - } // namespace constraints } // namespace valijson diff --git a/include/valijson/subschema.hpp b/include/valijson/subschema.hpp index bcc2666..bac2925 100644 --- a/include/valijson/subschema.hpp +++ b/include/valijson/subschema.hpp @@ -25,6 +25,12 @@ namespace valijson { class Subschema { public: + /// Typedef for custom new-/malloc-like function + typedef void * (*CustomAlloc)(size_t size); + + /// Typedef for custom free-like function + typedef void (*CustomFree)(void *); + /// Typedef the Constraint class into the local namespace for convenience typedef constraints::Constraint Constraint; @@ -33,9 +39,24 @@ public: typedef boost::function ApplyFunction; /** - * @brief Construct a new Subschema object with no constraints + * @brief Construct a new Subschema object */ - Subschema() { } + Subschema() + : allocFn(::operator new) + , freeFn(::operator delete) { } + + /** + * @brief Construct a new Subschema using custom memory management + * functions + * + * @parma allocFn malloc- or new-like function to allocate memory + * within Schema, such as for Subschema instances + * @param freeFn free-like function to free memory allocated with + * the `customAlloc` function + */ + Subschema(CustomAlloc allocFn, CustomFree freeFn) + : allocFn(allocFn) + , freeFn(freeFn) { } /** * @brief Clean up and free all memory managed by the Subschema @@ -46,7 +67,8 @@ public: for (std::vector::iterator itr = constraints.begin(); itr != constraints.end(); ++itr) { const Constraint *constraint = *itr; - delete constraint; + constraint->~Constraint(); + freeFn((void*)(constraint)); } constraints.clear(); } catch (const std::exception &e) { @@ -68,20 +90,7 @@ public: */ void addConstraint(const Constraint &constraint) { - constraints.push_back(constraint.clone()); - } - - /** - * @brief Add a constraint to this sub-schema - * - * This Subschema instance will take ownership of Constraint that is - * pointed to, and will free it when it is no longer needed. - * - * @param constraint Pointer to the Constraint to take ownership of - */ - void addConstraint(Constraint *constraint) - { - constraints.push_back(constraint); + constraints.push_back(constraint.clone(allocFn, freeFn)); } /** @@ -239,6 +248,12 @@ public: this->title = title; } +protected: + + CustomAlloc allocFn; + + CustomFree freeFn; + private: // Disable copy construction